@ainyc/canonry 5.0.0 → 5.1.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.
- package/README.md +1 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +24 -5
- package/assets/assets/{AuditHistoryPanel-vWUtVXOI.js → AuditHistoryPanel-9F_74jKS.js} +1 -1
- package/assets/assets/{BacklinksPage-CSzuMEuv.js → BacklinksPage-DmF2rbwy.js} +1 -1
- package/assets/assets/{HistoryPage-DtCTQ7CQ.js → HistoryPage-DKopwAjo.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-B7gTMWNs.js → MeasurementPropertyPage-Dpd_DYQv.js} +1 -1
- package/assets/assets/{ProjectPage-Bsm0_jUY.js → ProjectPage-b1-57SzP.js} +1 -1
- package/assets/assets/{RunRow-D5k4Rdo4.js → RunRow-BjrSRp6X.js} +1 -1
- package/assets/assets/{RunsPage-DIXBB2Om.js → RunsPage-BFrymZ7D.js} +1 -1
- package/assets/assets/{SettingsPage-wYhBm6Az.js → SettingsPage-DdVa6pLK.js} +1 -1
- package/assets/assets/{SiteHealthSection-YebzsgDh.js → SiteHealthSection-CizmiBjA.js} +3 -3
- package/assets/assets/{TrafficPage-DtnSRFO8.js → TrafficPage-N7sZgb9x.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DYQ6mpYq.js → TrafficSourceDetailPage-BNQmMJ5D.js} +1 -1
- package/assets/assets/{extract-error-message-BdChrkmo.js → extract-error-message-Bh9mRIz9.js} +1 -1
- package/assets/assets/{index-C_E2NRYY.js → index-BnR1Tu9j.js} +3 -3
- package/assets/assets/{react-sigma_core.esm.min-sKWUk_tG.js → react-sigma_core.esm.min-DGaYwjLZ.js} +1 -1
- package/assets/assets/{v2-overview-adapter-CkPt-sRK.js → v2-overview-adapter-eqN-8OK5.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-3WODA4JF.js → chunk-3DL3KV6C.js} +2 -0
- package/dist/{chunk-LJKAB4CX.js → chunk-66KGNC4U.js} +2 -2
- package/dist/{chunk-UMU3IBXM.js → chunk-LHHJVGH7.js} +39 -26
- package/dist/{chunk-B2XM6AQ6.js → chunk-MEQGGODM.js} +21 -9
- package/dist/{chunk-67NX4KVE.js → chunk-ZWVXUPLP.js} +128 -8
- package/dist/cli.js +6 -5
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-MGQRJW4V.js → intelligence-service-7XX5ZRYE.js} +2 -2
- package/dist/mcp.js +6 -7
- package/package.json +26 -11
package/assets/assets/{react-sigma_core.esm.min-sKWUk_tG.js → react-sigma_core.esm.min-DGaYwjLZ.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as Bt,t as S,r as C}from"./vendor-tanstack-ZXXkndVj.js";import{e as Ht,G as Wt}from"./SiteHealthSection-
|
|
1
|
+
import{g as Bt,t as S,r as C}from"./vendor-tanstack-ZXXkndVj.js";import{e as Ht,G as Wt}from"./SiteHealthSection-CizmiBjA.js";import"./index-BnR1Tu9j.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-lucide-CW2qe0uH.js";import"./vendor-markdown-B-Oq2NYq.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-Bxa_vFmq.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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as o,r as C}from"./vendor-tanstack-ZXXkndVj.js";import{y as M,B as A}from"./index-
|
|
1
|
+
import{j as o,r as C}from"./vendor-tanstack-ZXXkndVj.js";import{y as M,B as A}from"./index-BnR1Tu9j.js";import{M as $}from"./vendor-markdown-B-Oq2NYq.js";const H="Sources",y={copy:"Copy answer",copying:"Copying…",copied:"Copied",failed:"Could not copy. Select and copy the answer above."};function N({headingLevel:e}){return n=>{const r=[],s=i=>{i.type==="heading"&&i.depth&&r.push(i),i.children?.forEach(s)};s(n);const l=r.reduce((i,u)=>Math.min(i,u.depth),6);for(const i of r){const u=i.depth-l;i.depth=Math.min(6,e+u),i.data={...i.data,hProperties:{...i.data?.hProperties,"data-answer-heading-level":u+1}}}}}function R({answer:e}){const[n,r]=C.useState("idle"),s=C.useRef(!1),l=async()=>{if(!s.current){s.current=!0,r("copying");try{await navigator.clipboard.writeText(e),r("copied")}catch{r("failed")}finally{s.current=!1}}};return o.jsxs("div",{className:"mt-3 flex flex-wrap items-center gap-x-3",children:[o.jsx(A,{type:"button",variant:"ghost",className:"min-h-11 px-2","aria-disabled":n==="copying","aria-busy":n==="copying",onClick:()=>{l()},children:n==="copying"?y.copying:y.copy}),o.jsx("span",{role:"status",className:"text-sm text-secondary",children:n==="copied"?y.copied:n==="failed"?y.failed:""})]})}function L({children:e,headingLevel:n=4,copyable:r=!1}){return o.jsxs("div",{className:"answer-markdown",children:[o.jsx($,{remarkPlugins:[[N,{headingLevel:n}]],components:{p:({children:s})=>o.jsx("p",{className:"mb-3 whitespace-pre-wrap last:mb-0",children:s}),ul:({children:s})=>o.jsx("ul",{className:"mb-3 ml-5 list-disc space-y-1",children:s}),ol:({children:s,start:l})=>o.jsx("ol",{start:l,className:"mb-3 ml-5 list-decimal space-y-1",children:s}),pre:({children:s})=>o.jsx("pre",{className:"mb-3 overflow-x-auto whitespace-pre-wrap",children:s}),a:({children:s,href:l})=>{const i=M(l);return i?o.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",className:"text-link underline",children:s}):o.jsx("span",{children:s})},img:({alt:s})=>o.jsx("span",{children:s})},children:e}),r&&e.trim()?o.jsx(R,{answer:e},e):null]})}function F(e){const n=e[0];return n?e.every(r=>r.mode===n.mode&&r.scope.kind===n.scope.kind&&r.scope.key===n.scope.key&&r.queryClass===n.queryClass&&r.measurement.displayedRunId===n.measurement.displayedRunId):!0}function p(e){return e.state==="unavailable"?{numerator:null,denominator:null,reason:e.reason}:e.numerator===void 0||e.denominator===void 0||e.denominator<=0?{numerator:null,denominator:null,reason:"not_applicable"}:{numerator:e.numerator,denominator:e.denominator}}function I(e){return e.kind==="exact"?e.url:e.kind==="prefix"?`https://${e.host}${e.pathPrefix}/*`:`https://${e.host}/*`}function T(e){return e==="assigned"?"this-property":e==="sibling"?"another-property":e==="ownedUnmapped"?"owned-unassigned":e==="external"?"external":e==="ambiguous"?"multiple-properties":"invalid-url"}function _(e){return e==="assigned"?"positive":e==="external"?"neutral":e==="invalid"?"negative":"caution"}function k(e){return`target:${e.targetKey}:${e.queryId}:${e.executionNodeKey}`}function j(e,n,r){const s=new Map;if(!n)return s;const l=new Map(e.usageEdges.map(a=>[k(a),a.targetKey])),i=new Map(e.assignments.map(a=>[`${a.targetKey}:${a.queryId}`,a.queryClass])),u=new Map(e.usageEdges.map(a=>[k(a),i.get(`${a.targetKey}:${a.queryId}`)]));for(const a of n.evidence){if(r&&u.get(a.usageEdgeId)!==r)continue;const c=l.get(a.usageEdgeId);if(!c)continue;const m=s.get(c)??[];m.push({id:`${a.observationId}:${a.expectedSlotId}:${a.usageEdgeId}:${a.sourceUrl}`,kind:T(a.classification),query:a.queryText,provider:a.provider,location:a.location,url:a.sourceUrl,tone:_(a.classification),historical:a.historical||a.bridged}),s.set(c,m)}return s}function B(e){if(e.flags>0)return{label:"Review",tone:"caution"};const n=[e.mentionCoverage,e.citationCoverage].filter(r=>r.state==="unavailable").map(r=>r.reason);return n.includes("no_completed_run")?{label:"Not measured",tone:"neutral"}:n.includes("plan_v1")?{label:"Update setup",tone:"caution"}:n.includes("evidence_incomplete")?{label:"Evidence incomplete",tone:"caution"}:n.includes("no_population")?{label:"No queries",tone:"neutral"}:n.includes("not_applicable")?{label:"Not applicable",tone:"neutral"}:{label:"Complete",tone:"positive"}}function O(e){return e==="complete"?{label:"Complete",tone:"positive"}:e==="partial"?{label:"Partial",tone:"caution"}:e==="queued"?{label:"Queued",tone:"neutral"}:e==="running"?{label:"Running",tone:"neutral"}:e==="failed"?{label:"Failed",tone:"negative"}:{label:"Not measured",tone:"neutral"}}function U(e){if(!e)return"";const n=new Date(e);return Number.isFinite(n.getTime())?n.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"}):""}function q(e){const n=e.nextAction.count??e.flags.total;if(e.nextAction.kind==="review_flags")return`${n} flagged ${n===1?"result needs":"results need"} review.`;if(e.nextAction.kind==="complete_setup")return"Finish setup.";if(e.nextAction.kind==="republish_setup")return"Setup update required.";if(e.nextAction.kind==="run_measurement")return"Ready to measure."}function W({overview:e,activePlan:n,report:r,reportState:s=r?"ready":"loading",sort:l}){if(n.plan.schemaVersion!==2||e.mode!=="active-v2")throw new Error("The current overview requires an active version-two setup.");if(e.scope.kind!=="all"&&e.scope.kind!=="group")throw new Error("The current overview requires an All Properties or group scope.");const i=n.plan,u=new Map(i.targets.map(t=>[t.stableKey,t])),a=new Map(i.querySnapshots.map(t=>[t.queryId,t.queryText])),c=new Map;for(const t of i.assignments){if(e.queryClass!=="all"&&t.queryClass!==e.queryClass)continue;const d=a.get(t.queryId);if(!d)continue;const g=c.get(t.targetKey)??new Set;g.add(d),c.set(t.targetKey,g)}const m=r?.revision===n.revision&&r.run?.id===e.measurement.displayedRunId?r:null,K=e.measurement.displayedRunId===void 0||m?"ready":s==="error"||r!=null?"error":"loading",S=j(i,m,e.queryClass==="all"?void 0:e.queryClass),h=new Map;for(const t of i.groups)for(const d of t.targetKeys)h.has(d)||h.set(d,t.label);const x=e.properties.items.map(t=>{const d=u.get(t.targetKey),g=S.get(t.targetKey)??[];return{id:t.targetKey,name:t.label,mentionCoverage:p(t.mentionCoverage),citationCoverage:p(t.citationCoverage),status:B(t),providers:t.providers?.map(f=>({provider:f.provider,mentionCoverage:p(f.mentionCoverage),citationCoverage:p(f.citationCoverage)})),market:h.get(t.targetKey),assignedQueries:[...c.get(t.targetKey)??[]],urls:d?.urlMatchers.map(I)??[],evidence:g,evidenceState:K,historical:g.some(f=>f.historical)}}),b=e.namedShareOfVoice?.entries.map(t=>({name:t.label,coverage:{numerator:t.credits,denominator:e.namedShareOfVoice.denominator}})),E=e.properties.items.flatMap(t=>t.flags>0?[{id:`property:${t.targetKey}`,property:t.label,summary:`${t.flags} ${t.flags===1?"result needs":"results need"} review.`,tone:"caution",count:t.flags}]:[]);return{classReporting:"available",latestMeasurement:{status:O(e.measurement.state),completedSlots:e.measurement.completed,totalSlots:e.measurement.expected,date:U(e.measurement.completedAt),includesBridgedHistory:e.measurement.includesHistoricalData===!0},currentView:{scope:e.scope.kind==="group"?{kind:"group",...e.scope.key?{key:e.scope.key}:{}}:{kind:"all"},queryClass:e.queryClass,aggregate:{metrics:{propertiesMentioned:p(e.metrics.propertiesMentioned),mentionCoverage:p(e.metrics.mentionCoverage),citationCoverage:p(e.metrics.citationCoverage)},properties:x,...b?{shareOfVoice:b}:{}},propertyTotal:e.properties.totalEstimate??x.length,outcomes:e.outcomes,nextCursor:e.properties.nextCursor,...l?{sort:l}:{}},availableGroups:i.groups.map(t=>({id:t.stableKey,label:t.label})),...q(e)?{nextActionText:q(e)}:{},flaggedResultsTotal:e.flags.total,flaggedResults:E}}export{L as A,H as a,F as b,W as c,I as m};
|
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-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-BnR1Tu9j.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-ZXXkndVj.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-twS1M3FF.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-D-cUuLZo.js">
|
|
@@ -5716,6 +5716,8 @@ var apiKeyDtoSchema = z10.object({
|
|
|
5716
5716
|
* — surfaces don't recompute it (see the UI/CLI parity rule). Additive field.
|
|
5717
5717
|
*/
|
|
5718
5718
|
readOnly: z10.boolean(),
|
|
5719
|
+
/** Present on /keys/self: host-derived direct-bearer authority, never a mintable scope. */
|
|
5720
|
+
operator: z10.boolean().optional(),
|
|
5719
5721
|
createdAt: z10.string(),
|
|
5720
5722
|
lastUsedAt: z10.string().nullable(),
|
|
5721
5723
|
revokedAt: z10.string().nullable()
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
installSkills,
|
|
6
6
|
loadConfigRaw,
|
|
7
7
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-MEQGGODM.js";
|
|
9
9
|
import {
|
|
10
10
|
SKILL_MANIFEST_FILENAME,
|
|
11
11
|
SkillsClients
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-3DL3KV6C.js";
|
|
13
13
|
|
|
14
14
|
// src/skills-autosync.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -702,10 +702,10 @@ import {
|
|
|
702
702
|
wordpressSchemaDeployResultDtoSchema,
|
|
703
703
|
wordpressSchemaStatusResultDtoSchema,
|
|
704
704
|
wordpressStatusDtoSchema
|
|
705
|
-
} from "./chunk-
|
|
705
|
+
} from "./chunk-3DL3KV6C.js";
|
|
706
706
|
|
|
707
707
|
// src/intelligence-service.ts
|
|
708
|
-
import { eq as eq67, desc as desc29, asc as asc12, and as and57, ne as
|
|
708
|
+
import { eq as eq67, desc as desc29, asc as asc12, and as and57, ne as ne11, or as or16, inArray as inArray25, gte as gte18, lte as lte15, isNull as isNull12, sql as sql27, exists } from "drizzle-orm";
|
|
709
709
|
|
|
710
710
|
// ../db/src/client.ts
|
|
711
711
|
import { mkdirSync } from "fs";
|
|
@@ -11226,6 +11226,11 @@ function requireAdminSession(request) {
|
|
|
11226
11226
|
if (!role || role === UserRoles.admin) return;
|
|
11227
11227
|
throw forbidden(ADMIN_ONLY_MESSAGE);
|
|
11228
11228
|
}
|
|
11229
|
+
function requireOperator(request) {
|
|
11230
|
+
const principal = request.principal;
|
|
11231
|
+
if (request.operatorAccess === true && principal?.kind === "api-key" && !principal.viaCookie && !principal.projectId && !principal.delegatedUser) return;
|
|
11232
|
+
throw forbidden("Internal diagnostics require a host-approved operator API key. Customer accounts and scopes cannot grant operator access.");
|
|
11233
|
+
}
|
|
11229
11234
|
function requirePaidReadScope(request) {
|
|
11230
11235
|
const principal = request.principal;
|
|
11231
11236
|
if (!principal || principal.kind !== "api-key") return;
|
|
@@ -11500,6 +11505,7 @@ async function authPlugin(app, opts = {}) {
|
|
|
11500
11505
|
viaCookie: keyArrivedInCookie,
|
|
11501
11506
|
...delegatedUser ? { delegatedUser: { id: delegatedUser.id, name: delegatedUser.name, role: delegatedUser.role } } : {}
|
|
11502
11507
|
};
|
|
11508
|
+
request.operatorAccess = !keyArrivedInCookie && !key.projectId && !key.delegatedUserId && opts.operatorApiKeyIds?.includes(key.id) === true;
|
|
11503
11509
|
assertSameOriginWrite(request);
|
|
11504
11510
|
applyRoleGates(request);
|
|
11505
11511
|
applyScopedWriteGates(request);
|
|
@@ -26092,7 +26098,7 @@ function normalizeCompetitorList2(domains) {
|
|
|
26092
26098
|
}
|
|
26093
26099
|
|
|
26094
26100
|
// ../api-routes/src/history.ts
|
|
26095
|
-
import { and as and22, asc as asc3, count, desc as desc9, eq as eq27, gte as gte5, inArray as inArray11, like, or as or4 } from "drizzle-orm";
|
|
26101
|
+
import { and as and22, asc as asc3, count, desc as desc9, eq as eq27, gte as gte5, inArray as inArray11, like, ne as ne5, or as or4 } from "drizzle-orm";
|
|
26096
26102
|
|
|
26097
26103
|
// ../api-routes/src/notification-redaction.ts
|
|
26098
26104
|
var REDACTED_URL = {
|
|
@@ -26171,6 +26177,7 @@ async function historyRoutes(app) {
|
|
|
26171
26177
|
app.get("/projects/:name/history", async (request, reply) => {
|
|
26172
26178
|
const project = resolveProject(app.db, request.params.name);
|
|
26173
26179
|
const filters = [eq27(auditLog.projectId, project.id)];
|
|
26180
|
+
if (request.operatorAccess !== true) filters.push(ne5(auditLog.entityType, "telemetry"));
|
|
26174
26181
|
addAuditHistoryFilters(filters, request.query);
|
|
26175
26182
|
const rows = app.db.select().from(auditLog).where(and22(...filters)).orderBy(desc9(auditLog.createdAt), desc9(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
26176
26183
|
return reply.send(rows.map(formatAuditEntry));
|
|
@@ -26178,6 +26185,7 @@ async function historyRoutes(app) {
|
|
|
26178
26185
|
app.get("/history", async (request, reply) => {
|
|
26179
26186
|
const scopedProjectId = request.apiKey?.projectId;
|
|
26180
26187
|
const filters = scopedProjectId ? [eq27(auditLog.projectId, scopedProjectId)] : [];
|
|
26188
|
+
if (request.operatorAccess !== true) filters.push(ne5(auditLog.entityType, "telemetry"));
|
|
26181
26189
|
addAuditHistoryFilters(filters, request.query);
|
|
26182
26190
|
const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and22(...filters) : void 0).orderBy(desc9(auditLog.createdAt), desc9(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
26183
26191
|
return reply.send(rows.map(formatAuditEntry));
|
|
@@ -27525,7 +27533,7 @@ function nonSubresourceReferralPathCondition() {
|
|
|
27525
27533
|
}
|
|
27526
27534
|
|
|
27527
27535
|
// ../api-routes/src/report.ts
|
|
27528
|
-
import { and as and29, desc as desc14, eq as eq33, gte as gte8, inArray as inArray15, lt as lt5, lte as lte6, ne as
|
|
27536
|
+
import { and as and29, desc as desc14, eq as eq33, gte as gte8, inArray as inArray15, lt as lt5, lte as lte6, ne as ne6, or as or5, sql as sql11 } from "drizzle-orm";
|
|
27529
27537
|
|
|
27530
27538
|
// ../api-routes/src/content.ts
|
|
27531
27539
|
import crypto23 from "crypto";
|
|
@@ -31308,7 +31316,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
31308
31316
|
const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
|
|
31309
31317
|
and29(
|
|
31310
31318
|
eq33(trafficSources.projectId, projectId),
|
|
31311
|
-
|
|
31319
|
+
ne6(trafficSources.status, TrafficSourceStatuses.archived)
|
|
31312
31320
|
)
|
|
31313
31321
|
).all();
|
|
31314
31322
|
if (sourceRows.length === 0) return null;
|
|
@@ -31334,7 +31342,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
31334
31342
|
db.select({ total: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
31335
31343
|
and29(
|
|
31336
31344
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
31337
|
-
|
|
31345
|
+
ne6(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
31338
31346
|
gte8(crawlerEventsHourly.tsHour, windowStartIso),
|
|
31339
31347
|
exclusiveEnd ? lt5(crawlerEventsHourly.tsHour, windowEndIso) : lte6(crawlerEventsHourly.tsHour, windowEndIso)
|
|
31340
31348
|
)
|
|
@@ -38346,7 +38354,7 @@ var routeCatalog = [
|
|
|
38346
38354
|
method: "get",
|
|
38347
38355
|
path: "/api/v1/operations/logs",
|
|
38348
38356
|
summary: "Read bounded, redacted runtime logs",
|
|
38349
|
-
description: "Requires logs.read (or wildcard)
|
|
38357
|
+
description: "Requires a direct bearer API key approved in the host CANONRY_OPERATOR_KEY_IDS allowlist, plus logs.read (or wildcard). Customer admin roles, scopes alone, browser sessions, OAuth/delegated keys, and project-scoped keys cannot grant access. Includes application and HTTP diagnostics, separate from audit history. File-backed hosts retain logs across restarts; inspect retention, retentionPolicy, dropped, and captureErrors. Filters apply before pagination and must remain unchanged when resuming a cursor. Cursors expire on retention eviction.",
|
|
38350
38358
|
tags: ["operations"],
|
|
38351
38359
|
parameters: [
|
|
38352
38360
|
{ name: "limit", in: "query", required: false, description: "Maximum entries (default 100).", schema: { type: "integer", minimum: 1, maximum: 200, default: 100 } },
|
|
@@ -38359,7 +38367,7 @@ var routeCatalog = [
|
|
|
38359
38367
|
200: jsonResponse("Runtime log page with retention and capture-loss metadata.", "OperationalLogListDto"),
|
|
38360
38368
|
400: errorResponse("Invalid filters or expired cursor."),
|
|
38361
38369
|
401: errorResponse("Authentication required."),
|
|
38362
|
-
403: errorResponse("
|
|
38370
|
+
403: errorResponse("Host-approved operator authority and instance logs.read permission required."),
|
|
38363
38371
|
501: errorResponse("This deployment does not provide operational logs.")
|
|
38364
38372
|
}
|
|
38365
38373
|
},
|
|
@@ -38367,9 +38375,11 @@ var routeCatalog = [
|
|
|
38367
38375
|
method: "get",
|
|
38368
38376
|
path: "/api/v1/telemetry",
|
|
38369
38377
|
summary: "Get telemetry status",
|
|
38378
|
+
description: "Internal surface. Requires a direct bearer API key approved in the host CANONRY_OPERATOR_KEY_IDS allowlist; customer admin roles and wildcard scopes alone are insufficient.",
|
|
38370
38379
|
tags: ["telemetry"],
|
|
38371
38380
|
responses: {
|
|
38372
38381
|
200: jsonResponse("Telemetry status returned.", "TelemetryStatusDto"),
|
|
38382
|
+
403: errorResponse("Host-approved operator authority required."),
|
|
38373
38383
|
501: errorResponse("Telemetry status is not available.")
|
|
38374
38384
|
}
|
|
38375
38385
|
},
|
|
@@ -38377,7 +38387,7 @@ var routeCatalog = [
|
|
|
38377
38387
|
method: "put",
|
|
38378
38388
|
path: "/api/v1/telemetry",
|
|
38379
38389
|
summary: "Update telemetry status",
|
|
38380
|
-
description: "Requires settings.write. The response reports the configured preference and effective state; deployment/environment opt-outs take precedence.",
|
|
38390
|
+
description: "Requires host-approved direct-bearer operator authority and settings.write. The response reports the configured preference and effective state; deployment/environment opt-outs take precedence.",
|
|
38381
38391
|
tags: ["telemetry"],
|
|
38382
38392
|
requestBody: {
|
|
38383
38393
|
required: true,
|
|
@@ -38396,7 +38406,7 @@ var routeCatalog = [
|
|
|
38396
38406
|
responses: {
|
|
38397
38407
|
200: jsonResponse("Telemetry updated.", "TelemetryStatusDto"),
|
|
38398
38408
|
400: errorResponse("Invalid telemetry request."),
|
|
38399
|
-
403: errorResponse("The credential lacks settings.write."),
|
|
38409
|
+
403: errorResponse("The credential lacks host-approved operator authority or settings.write."),
|
|
38400
38410
|
501: errorResponse("Telemetry configuration is not available.")
|
|
38401
38411
|
}
|
|
38402
38412
|
},
|
|
@@ -42777,7 +42787,7 @@ async function keysRoutes(app) {
|
|
|
42777
42787
|
if (!row) {
|
|
42778
42788
|
throw notFound("API key", id);
|
|
42779
42789
|
}
|
|
42780
|
-
return toApiKeyDto({ ...row, scopes: request.apiKey?.scopes ?? row.scopes }, projectNameById(app.db));
|
|
42790
|
+
return { ...toApiKeyDto({ ...row, scopes: request.apiKey?.scopes ?? row.scopes }, projectNameById(app.db)), operator: request.operatorAccess === true };
|
|
42781
42791
|
});
|
|
42782
42792
|
app.post("/keys", async (request) => {
|
|
42783
42793
|
requireAdminSession(request);
|
|
@@ -43011,13 +43021,15 @@ async function snapshotRoutes(app, opts) {
|
|
|
43011
43021
|
|
|
43012
43022
|
// ../api-routes/src/telemetry.ts
|
|
43013
43023
|
async function telemetryRoutes(app, opts) {
|
|
43014
|
-
app.get("/telemetry", async () => {
|
|
43024
|
+
app.get("/telemetry", async (request) => {
|
|
43025
|
+
requireOperator(request);
|
|
43015
43026
|
if (!opts.getTelemetryStatus) {
|
|
43016
43027
|
throw notImplemented("Telemetry status is not available in this deployment");
|
|
43017
43028
|
}
|
|
43018
43029
|
return normalizeTelemetryStatus(opts.getTelemetryStatus());
|
|
43019
43030
|
});
|
|
43020
43031
|
app.put("/telemetry", async (request) => {
|
|
43032
|
+
requireOperator(request);
|
|
43021
43033
|
requireScope(request, SETTINGS_WRITE_SCOPE);
|
|
43022
43034
|
if (!opts.setTelemetryEnabled) {
|
|
43023
43035
|
throw notImplemented("Telemetry configuration is not available in this deployment");
|
|
@@ -43065,7 +43077,7 @@ async function telemetryRoutes(app, opts) {
|
|
|
43065
43077
|
// ../api-routes/src/operational-logs.ts
|
|
43066
43078
|
async function operationalLogsRoutes(app, opts = {}) {
|
|
43067
43079
|
app.get("/operations/logs", async (request) => {
|
|
43068
|
-
|
|
43080
|
+
requireOperator(request);
|
|
43069
43081
|
requireScope(request, "logs.read");
|
|
43070
43082
|
if (request.apiKey?.projectId) {
|
|
43071
43083
|
throw forbidden("This API key is scoped to one project and cannot read instance operational diagnostics.");
|
|
@@ -47198,7 +47210,7 @@ async function googleRoutes(app, opts) {
|
|
|
47198
47210
|
|
|
47199
47211
|
// ../api-routes/src/google-marketing.ts
|
|
47200
47212
|
import crypto33 from "crypto";
|
|
47201
|
-
import { and as and38, desc as desc20, eq as eq45, isNull as isNull6, lt as lt6, ne as
|
|
47213
|
+
import { and as and38, desc as desc20, eq as eq45, isNull as isNull6, lt as lt6, ne as ne7, or as or9, sql as sql16 } from "drizzle-orm";
|
|
47202
47214
|
import { z as z4 } from "zod";
|
|
47203
47215
|
var snapshotPageQuerySchema = z4.object({
|
|
47204
47216
|
limit: z4.coerce.number().int().min(1).max(GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX).optional(),
|
|
@@ -48699,7 +48711,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
48699
48711
|
const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and38(
|
|
48700
48712
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
48701
48713
|
eq45(conversionTrackingContracts.name, body.name),
|
|
48702
|
-
|
|
48714
|
+
ne7(conversionTrackingContracts.id, existing.id)
|
|
48703
48715
|
)).get();
|
|
48704
48716
|
if (duplicate) throw alreadyExists("Conversion tracking contract", body.name);
|
|
48705
48717
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -48788,7 +48800,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
48788
48800
|
|
|
48789
48801
|
// ../api-routes/src/ads.ts
|
|
48790
48802
|
import crypto36 from "crypto";
|
|
48791
|
-
import { eq as eq47, and as and40, asc as asc9, desc as desc21, gt as gt3, gte as gte12, lt as lt7, lte as lte11, ne as
|
|
48803
|
+
import { eq as eq47, and as and40, asc as asc9, desc as desc21, gt as gt3, gte as gte12, lt as lt7, lte as lte11, ne as ne8, inArray as inArray20, or as or11, isNull as isNull8, isNotNull as isNotNull4, sql as sql18 } from "drizzle-orm";
|
|
48792
48804
|
|
|
48793
48805
|
// ../api-routes/src/ads-activation.ts
|
|
48794
48806
|
import crypto34 from "crypto";
|
|
@@ -52475,7 +52487,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
52475
52487
|
);
|
|
52476
52488
|
const staleReconcileWhere = and40(
|
|
52477
52489
|
lt7(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
52478
|
-
|
|
52490
|
+
ne8(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
52479
52491
|
or11(
|
|
52480
52492
|
eq47(adsOperations.reconcileStrategy, AdsReconcileStrategies.known_entity),
|
|
52481
52493
|
and40(
|
|
@@ -52492,7 +52504,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
52492
52504
|
retryableStateWhere
|
|
52493
52505
|
);
|
|
52494
52506
|
const exhaustedRows = app.db.select().from(adsOperations).where(and40(
|
|
52495
|
-
|
|
52507
|
+
ne8(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
52496
52508
|
gte12(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
52497
52509
|
or11(
|
|
52498
52510
|
and40(
|
|
@@ -52507,7 +52519,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
52507
52519
|
),
|
|
52508
52520
|
or11(
|
|
52509
52521
|
isNull8(adsOperations.errorCode),
|
|
52510
|
-
|
|
52522
|
+
ne8(adsOperations.errorCode, ADS_RECONCILIATION_QUARANTINED)
|
|
52511
52523
|
)
|
|
52512
52524
|
)).orderBy(asc9(adsOperations.updatedAt)).limit(config.batchSize).all();
|
|
52513
52525
|
for (const row of exhaustedRows) {
|
|
@@ -57985,7 +57997,7 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
57985
57997
|
}
|
|
57986
57998
|
|
|
57987
57999
|
// ../api-routes/src/backlinks-filter.ts
|
|
57988
|
-
import { and as and44, ne as
|
|
58000
|
+
import { and as and44, ne as ne9, notLike } from "drizzle-orm";
|
|
57989
58001
|
var BACKLINK_FILTER_PATTERNS = [
|
|
57990
58002
|
"*.google.com",
|
|
57991
58003
|
"*.googleusercontent.com",
|
|
@@ -58002,10 +58014,10 @@ function backlinkCrawlerExclusionClause() {
|
|
|
58002
58014
|
for (const pattern of BACKLINK_FILTER_PATTERNS) {
|
|
58003
58015
|
if (pattern.startsWith("*.")) {
|
|
58004
58016
|
const suffix = pattern.slice(2);
|
|
58005
|
-
conditions.push(
|
|
58017
|
+
conditions.push(ne9(backlinkDomains.linkingDomain, suffix));
|
|
58006
58018
|
conditions.push(notLike(backlinkDomains.linkingDomain, `%.${suffix}`));
|
|
58007
58019
|
} else {
|
|
58008
|
-
conditions.push(
|
|
58020
|
+
conditions.push(ne9(backlinkDomains.linkingDomain, pattern));
|
|
58009
58021
|
}
|
|
58010
58022
|
}
|
|
58011
58023
|
const combined = and44(...conditions);
|
|
@@ -80283,7 +80295,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
80283
80295
|
];
|
|
80284
80296
|
|
|
80285
80297
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
80286
|
-
import { and as and52, eq as eq61, gte as gte15, inArray as inArray22, ne as
|
|
80298
|
+
import { and as and52, eq as eq61, gte as gte15, inArray as inArray22, ne as ne10, sql as sql24 } from "drizzle-orm";
|
|
80287
80299
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
80288
80300
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
80289
80301
|
function isCloudflareDirectPush(source) {
|
|
@@ -80324,7 +80336,7 @@ function loadProbes(ctx) {
|
|
|
80324
80336
|
const rows = ctx.db.select().from(trafficSources).where(
|
|
80325
80337
|
and52(
|
|
80326
80338
|
eq61(trafficSources.projectId, ctx.project.id),
|
|
80327
|
-
|
|
80339
|
+
ne10(trafficSources.status, TrafficSourceStatuses.archived)
|
|
80328
80340
|
)
|
|
80329
80341
|
).all();
|
|
80330
80342
|
return rows.map((r) => ({
|
|
@@ -84465,6 +84477,7 @@ async function apiRoutes(app, opts) {
|
|
|
84465
84477
|
});
|
|
84466
84478
|
if (!opts.skipAuth) {
|
|
84467
84479
|
await authPlugin(api, {
|
|
84480
|
+
operatorApiKeyIds: opts.operatorApiKeyIds,
|
|
84468
84481
|
researchAllowViewers: opts.researchAllowViewers,
|
|
84469
84482
|
// A bearer that is not an api key is tried as an OAuth access token.
|
|
84470
84483
|
// Wired unconditionally: the table is empty until an operator registers
|
|
@@ -85348,7 +85361,7 @@ function analyzableRunPredicates(projectId) {
|
|
|
85348
85361
|
// Defensive: RunCoordinator already skips probes before analyzeAndPersist
|
|
85349
85362
|
// is called, but a future call site invoking it directly for a probe must
|
|
85350
85363
|
// still not pollute the intelligence window.
|
|
85351
|
-
|
|
85364
|
+
ne11(runs.trigger, RunTriggers.probe)
|
|
85352
85365
|
];
|
|
85353
85366
|
}
|
|
85354
85367
|
function readStoredGroundingSources(rawResponse) {
|
|
@@ -85936,7 +85949,7 @@ var IntelligenceService = class {
|
|
|
85936
85949
|
eq67(runs.kind, RunKinds["answer-visibility"]),
|
|
85937
85950
|
or16(eq67(runs.status, "completed"), eq67(runs.status, "partial")),
|
|
85938
85951
|
// Defensive — see top of file.
|
|
85939
|
-
|
|
85952
|
+
ne11(runs.trigger, RunTriggers.probe)
|
|
85940
85953
|
)
|
|
85941
85954
|
).orderBy(desc29(runs.createdAt), desc29(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
|
|
85942
85955
|
const recentGroups = groupRunsByCreatedAt(recentRunRows);
|
|
@@ -115,7 +115,7 @@ import {
|
|
|
115
115
|
trafficEventKindSchema,
|
|
116
116
|
trafficSeriesGranularitySchema,
|
|
117
117
|
visibilityReportRequestSchema
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-3DL3KV6C.js";
|
|
119
119
|
|
|
120
120
|
// src/cli-error.ts
|
|
121
121
|
function isMachineFormat(format) {
|
|
@@ -190,6 +190,13 @@ var dashboardManagedSweepsSchema = z.boolean().nullish();
|
|
|
190
190
|
var researchAllowViewersSchema = z.boolean().nullish();
|
|
191
191
|
var researchViewerDailyRunLimitSchema = z.number().int().positive().nullish();
|
|
192
192
|
var dashboardManagedRunKindsSchema = z.array(schedulableRunKindSchema).nullish();
|
|
193
|
+
function resolveOperatorApiKeyIds(source) {
|
|
194
|
+
const raw = source.CANONRY_OPERATOR_KEY_IDS?.trim();
|
|
195
|
+
if (!raw) return [];
|
|
196
|
+
const parsed = z.array(z.string().regex(/^[\w-]{1,256}$/)).max(100).safeParse(raw.split(",").map((id) => id.trim()));
|
|
197
|
+
if (!parsed.success) throw new Error("CANONRY_OPERATOR_KEY_IDS must contain at most 100 comma-separated API key IDs (letters, digits, underscores, hyphens; no wildcards).");
|
|
198
|
+
return [...new Set(parsed.data)];
|
|
199
|
+
}
|
|
193
200
|
var envSchema = z.object({
|
|
194
201
|
DATABASE_URL: z.string().default("postgresql://aeo:aeo@postgres:5432/aeo_platform"),
|
|
195
202
|
API_PORT: z.coerce.number().int().positive().default(3e3),
|
|
@@ -10492,7 +10499,7 @@ var canonryMcpTools = [
|
|
|
10492
10499
|
defineTool({
|
|
10493
10500
|
name: "canonry_key_self",
|
|
10494
10501
|
title: "Get current API key identity",
|
|
10495
|
-
description: "Read safe metadata for the credential backing this MCP connection, including
|
|
10502
|
+
description: "Read safe metadata for the credential backing this MCP connection, including scopes, project reach, read-only status, and host-derived operator authority. It never exposes the bearer token or stored hash and cannot grant authority.",
|
|
10496
10503
|
access: "read",
|
|
10497
10504
|
tier: "core",
|
|
10498
10505
|
inputSchema: emptyInputSchema,
|
|
@@ -10503,8 +10510,9 @@ var canonryMcpTools = [
|
|
|
10503
10510
|
}),
|
|
10504
10511
|
defineTool({
|
|
10505
10512
|
name: "canonry_logs_list",
|
|
10513
|
+
requiresOperator: true,
|
|
10506
10514
|
title: "Read runtime logs",
|
|
10507
|
-
description: "Read bounded, redacted runtime logs, including application and HTTP failures. Filter by actor, request, run, project, level, module, or time. Inspect retention, retentionPolicy, dropped, and captureErrors for coverage; file-backed hosts retain logs across restarts. Separate from audit history. Requires instance-wide logs.read (or wildcard)
|
|
10515
|
+
description: "Read bounded, redacted runtime logs, including application and HTTP failures. Filter by actor, request, run, project, level, module, or time. Inspect retention, retentionPolicy, dropped, and captureErrors for coverage; file-backed hosts retain logs across restarts. Separate from audit history. Requires a host-approved operator bearer and instance-wide logs.read (or wildcard). Customer admins, browser/OAuth/delegated sessions, and project-scoped keys cannot grant access. Cursors expire on retention eviction; reuse with the same filters. No provider calls.",
|
|
10508
10516
|
access: "read",
|
|
10509
10517
|
tier: "setup",
|
|
10510
10518
|
inputSchema: logQuerySchema,
|
|
@@ -10515,8 +10523,9 @@ var canonryMcpTools = [
|
|
|
10515
10523
|
}),
|
|
10516
10524
|
defineTool({
|
|
10517
10525
|
name: "canonry_telemetry_update",
|
|
10526
|
+
requiresOperator: true,
|
|
10518
10527
|
title: "Update server telemetry preference",
|
|
10519
|
-
description: "Set the connected server telemetry preference with explicit approval and settings.write. Returns effective state including environment overrides. Does not change the agent machine configuration.",
|
|
10528
|
+
description: "Set the connected server telemetry preference with explicit approval, host-approved operator authority, and settings.write. Customer roles and scopes alone cannot grant operator access. Returns effective state including environment overrides. Does not change the agent machine configuration.",
|
|
10520
10529
|
access: "write",
|
|
10521
10530
|
requiredScope: "settings.write",
|
|
10522
10531
|
tier: "setup",
|
|
@@ -10541,8 +10550,9 @@ var canonryMcpTools = [
|
|
|
10541
10550
|
}),
|
|
10542
10551
|
defineTool({
|
|
10543
10552
|
name: "canonry_telemetry_get",
|
|
10553
|
+
requiresOperator: true,
|
|
10544
10554
|
title: "Get telemetry status",
|
|
10545
|
-
description: "Read
|
|
10555
|
+
description: "Read internal server telemetry status and effective reason. Requires a host-approved operator bearer, not a customer admin role or scopes alone. Does not change telemetry collection.",
|
|
10546
10556
|
access: "read",
|
|
10547
10557
|
tier: "setup",
|
|
10548
10558
|
inputSchema: emptyInputSchema,
|
|
@@ -13063,7 +13073,7 @@ var OPERATIONS_GUIDE = {
|
|
|
13063
13073
|
"guidance": "Read the stored report for the selected project and period. Retain evidence dates, scope, sample sizes, missing data, and separate mention/citation signals; do not generate fresh runs implicitly."
|
|
13064
13074
|
}
|
|
13065
13075
|
},
|
|
13066
|
-
"markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `operations`, `prospecting`, `measurement`, `integrations`,\n`reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`next` lists stored reads. Optional `actions` lists loaded tools for work that\nrequires approval; listing an action does not authorize or execute it.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Prospecting:** generate a one-shot company snapshot without creating a project.\nInspect stored provider settings first. Agree on the company, domain, selected\nproviders, and queries before starting the quota-spending snapshot action.\nBrowser-only selection requires manual queries. Progressive stdio help offers\nthe discovery toolkit when this connection permits snapshots; load it, then\ncall help again. Fixed catalogs offer only already available actions. Read-only\nand restricted connections must not bypass missing snapshot access.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` to inspect the current credential's scopes and project\nboundary without exposing its token. `canonry_settings_get` and\n`canonry_telemetry_get` describe the connected server, not the agent's local\nmachine. Telemetry reports configured preference, effective state, and any\nenvironment override; inspecting status never creates an anonymous identifier.\nAfter approval, `canonry_telemetry_update` changes that preference and\n`canonry_provider_settings_update` changes an already-configured provider's\nmodel/quota. Both require `settings.write`; neither accepts credentials.\n\n`canonry_logs_list` reads bounded, redacted runtime events from both the\napplication logger and Fastify request/error logging. It requires an\ninstance-wide `logs.read` grant (or wildcard), and\nadmin role for signed-in users. Project-scoped keys cannot use it, even with a\nproject filter. A `logs.read`-only key is read-only automatically, without a\nsecond `read` marker. Named `*.read` scopes cannot grant mutations; an explicit\nwrite grant is needed and remains subject to its route gates. Returned messages\nare sanitized and bounded; raw request or response bodies, headers, cookies,\nprovider payloads, and stacks are not\npart of the queryable surface. The same secret-redaction policy runs before\nconsole output and storage. Do not deliberately log secrets: redaction is a\ndefense in depth, not permission to put credentials into diagnostic strings.\nOpaque escaped payloads containing secret assignments are omitted when safe\npartial masking cannot be guaranteed; correlate their retained error codes and IDs.\n\nFile-backed hosts retain runtime logs in SQLite across restarts, bounded to\n10,000 events and seven days. In-memory hosts report `retention: \"process\"`.\nFilter by `actor`, `requestId`, `runId`, `projectId`, `module`, `level`, or an\ninclusive `since`/`until` interval. Keep filters unchanged when resuming an\nopaque cursor; retention eviction can invalidate it. Inspect `retentionPolicy`,\n`captureErrors`, `dropped`, `truncated`, and `retention` before drawing\nconclusions. Missing logs are not proof that an action did not happen. Use\n`canonry_project_history` or `canonry_history_global` for persistent audit events;\noffset pages have deterministic ordering but are not snapshots of concurrent writes.\n\nAudit `actor` comes from authenticated identity (`user:<id>` or `api-key:<id>`),\nnot a caller-supplied header. A delegated MCP credential records its originating\nuser as actor and the actual credential in `credentialId`. `requestId` correlates\nHTTP events; `userAgent` and `actorSession` are bounded, untrusted client hints,\nnever identity or permission grants. Older audit rows are not backfilled with\nidentities the server cannot prove.\n\nBoth shipped HTTP hosts issue restart-safe UUID request IDs and return them in\n`x-request-id`. Use that value to correlate a CLI/API failure with log entries;\nHTTP diagnostics retain the method and route template, not raw URL parameters.\nRequest-bound loggers retain completion attribution, while generic background\ncontinuations stop inheriting caller identity after the response completes.\nCapture covers the owning server process after initialization, not arbitrary\nconsole output, other worker processes, or host/container logs. Run one server\ninstance per process and database, as required by the single-tenant deployment\nmodel; this is not a cross-tenant or distributed log collector.\n\nFor CLI use, settings reads are remote. Google setup and telemetry retain their\nlocal defaults: pass `--target server` explicitly to configure the connected\nserver. `schedule list <project>` lists all schedule kinds, and\n`notify events --target server` discovers the server's event catalog.\n\nMCP returns legacy text JSON plus structured results. Objects keep their shape;\narrays use `{items: [...]}` in `structuredContent`, and scalars use `{value: ...}`.\nErrors preserve the existing envelope and CLI exit codes: HTTP 4xx (including\n429 policy limits) use exit 1; HTTP 5xx use exit 2. Server-provided `Retry-After`\nand request IDs are exposed as `retryAfterMs` and `requestId` when available;\nclients do not infer retryability from HTTP 429 or retry automatically.\nFor a write with an ambiguous outcome, inspect saved state or its receipt before\nretrying; a retry hint is not proof that repeating a write is safe.\n\n### Action boundaries\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
|
|
13076
|
+
"markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `operations`, `prospecting`, `measurement`, `integrations`,\n`reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`next` lists stored reads. Optional `actions` lists loaded tools for work that\nrequires approval; listing an action does not authorize or execute it.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Prospecting:** generate a one-shot company snapshot without creating a project.\nInspect stored provider settings first. Agree on the company, domain, selected\nproviders, and queries before starting the quota-spending snapshot action.\nBrowser-only selection requires manual queries. Progressive stdio help offers\nthe discovery toolkit when this connection permits snapshots; load it, then\ncall help again. Fixed catalogs offer only already available actions. Read-only\nand restricted connections must not bypass missing snapshot access.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` (CLI `canonry key whoami --format json`) to inspect the\ncurrent credential's scopes, project boundary, and host-derived `operator`\nauthority without exposing its token. Missing `operator` means unapproved.\n`canonry_settings_get` and\n`canonry_telemetry_get` describe the connected server, not the agent's local\nmachine. Telemetry reports configured preference, effective state, and any\nenvironment override; inspecting status never creates an anonymous identifier.\nAfter approval, `canonry_telemetry_update` changes that preference and\n`canonry_provider_settings_update` changes an already-configured provider's\nmodel/quota. Both require `settings.write`; neither accepts credentials.\nServer telemetry reads and updates additionally require operator authority.\nOrdinary audit-history reads omit internal telemetry events and their state.\n\nOperator authority is deny-by-default and separate from customer admin roles.\nThe deployment owner must approve a dedicated, instance-wide API key's ID in\nthe server environment variable `CANONRY_OPERATOR_KEY_IDS` (comma-separated IDs),\nthen restart the server. Empty/unset approves nobody; wildcards are invalid.\nKeep the bearer private to internal operators; never approve a customer-held or\nshared proxy/bootstrap key. Use `logs.read` for read-only diagnostics, adding\n`settings.write` only when telemetry control is required. Ordinary key creation,\naccount roles, OAuth consent, and caller headers cannot grant operator status.\nRevoking an approved key invalidates it immediately. Host enrollment is a trust\nbootstrap step, intentionally unavailable through customer-facing APIs.\nAPI, CLI, and MCP enforce the same boundary; MCP hides internal tools unless\nthe server confirms operator authority, including in explicit read-only mode.\nProject analytics, research, and normal project permissions are unchanged.\n\n`canonry_logs_list` reads bounded, redacted runtime events from both the\napplication logger and Fastify request/error logging. It requires an\ninstance-wide `logs.read` grant (or wildcard) and a host-approved direct bearer.\nBrowser sessions, OAuth/delegated credentials, customer admins, and project-scoped\nkeys cannot use it, even with a project filter or a matching allowlist ID.\nA `logs.read`-only key is read-only automatically, without a\nsecond `read` marker. Named `*.read` scopes cannot grant mutations; an explicit\nwrite grant is needed and remains subject to its route gates. Returned messages\nare sanitized and bounded; raw request or response bodies, headers, cookies,\nprovider payloads, and stacks are not\npart of the queryable surface. The same secret-redaction policy runs before\nconsole output and storage. Do not deliberately log secrets: redaction is a\ndefense in depth, not permission to put credentials into diagnostic strings.\nOpaque escaped payloads containing secret assignments are omitted when safe\npartial masking cannot be guaranteed; correlate their retained error codes and IDs.\n\nFile-backed hosts retain runtime logs in SQLite across restarts, bounded to\n10,000 events and seven days. In-memory hosts report `retention: \"process\"`.\nFilter by `actor`, `requestId`, `runId`, `projectId`, `module`, `level`, or an\ninclusive `since`/`until` interval. Keep filters unchanged when resuming an\nopaque cursor; retention eviction can invalidate it. Inspect `retentionPolicy`,\n`captureErrors`, `dropped`, `truncated`, and `retention` before drawing\nconclusions. Missing logs are not proof that an action did not happen. Use\n`canonry_project_history` or `canonry_history_global` for persistent audit events;\noffset pages have deterministic ordering but are not snapshots of concurrent writes.\n\nAudit `actor` comes from authenticated identity (`user:<id>` or `api-key:<id>`),\nnot a caller-supplied header. A delegated MCP credential records its originating\nuser as actor and the actual credential in `credentialId`. `requestId` correlates\nHTTP events; `userAgent` and `actorSession` are bounded, untrusted client hints,\nnever identity or permission grants. Older audit rows are not backfilled with\nidentities the server cannot prove.\n\nBoth shipped HTTP hosts issue restart-safe UUID request IDs and return them in\n`x-request-id`. Use that value to correlate a CLI/API failure with log entries;\nHTTP diagnostics retain the method and route template, not raw URL parameters.\nRequest-bound loggers retain completion attribution, while generic background\ncontinuations stop inheriting caller identity after the response completes.\nCapture covers the owning server process after initialization, not arbitrary\nconsole output, other worker processes, or host/container logs. Run one server\ninstance per process and database, as required by the single-tenant deployment\nmodel; this is not a cross-tenant or distributed log collector.\n\nFor CLI use, settings reads are remote. Google setup and telemetry retain their\nlocal defaults: pass `--target server` explicitly to configure the connected\nserver. `schedule list <project>` lists all schedule kinds, and\n`notify events --target server` discovers the server's event catalog.\n\nMCP returns legacy text JSON plus structured results. Objects keep their shape;\narrays use `{items: [...]}` in `structuredContent`, and scalars use `{value: ...}`.\nErrors preserve the existing envelope and CLI exit codes: HTTP 4xx (including\n429 policy limits) use exit 1; HTTP 5xx use exit 2. Server-provided `Retry-After`\nand request IDs are exposed as `retryAfterMs` and `requestId` when available;\nclients do not infer retryability from HTTP 429 or retry automatically.\nFor a write with an ambiguous outcome, inspect saved state or its receipt before\nretrying; a retry hint is not proof that repeating a write is safe.\n\n### Action boundaries\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
|
|
13067
13077
|
};
|
|
13068
13078
|
|
|
13069
13079
|
// src/mcp/operations-guide.ts
|
|
@@ -13117,7 +13127,7 @@ function createCanonryMcpServerWithCatalog(options = {}) {
|
|
|
13117
13127
|
});
|
|
13118
13128
|
server.validateToolInput = async (_tool, args) => args;
|
|
13119
13129
|
const entries = [];
|
|
13120
|
-
for (const registryTool of getCanonryMcpTools(scope, options.tiers, options.credentialScopes)) {
|
|
13130
|
+
for (const registryTool of getCanonryMcpTools(scope, options.tiers, options.credentialScopes, options.operator)) {
|
|
13121
13131
|
const tool = registryTool;
|
|
13122
13132
|
const handler = tool.handler;
|
|
13123
13133
|
const registered = server.registerTool(
|
|
@@ -13189,10 +13199,11 @@ function registerMetaTools(server, catalog, opts) {
|
|
|
13189
13199
|
})
|
|
13190
13200
|
);
|
|
13191
13201
|
}
|
|
13192
|
-
function getCanonryMcpTools(scope = "all", tiers, credentialScopes) {
|
|
13202
|
+
function getCanonryMcpTools(scope = "all", tiers, credentialScopes, operator = false) {
|
|
13193
13203
|
const readOnly = scope === "read-only" || credentialScopes !== void 0 && isReadOnlyKey(credentialScopes);
|
|
13194
13204
|
const restricted = credentialScopes && restrictedWriteScopes(credentialScopes);
|
|
13195
|
-
const
|
|
13205
|
+
const authorized = canonryMcpTools.filter((tool) => !tool.requiresOperator || operator);
|
|
13206
|
+
const byScope = readOnly ? authorized.filter((tool) => tool.access === "read") : authorized.filter((tool) => {
|
|
13196
13207
|
if (!restricted || tool.access === "read") return true;
|
|
13197
13208
|
if (tool.requiredScope && restricted.includes(tool.requiredScope)) return true;
|
|
13198
13209
|
return restricted.some((grant) => grant !== RESEARCH_RUN_SCOPE) && tool.tier === "ads";
|
|
@@ -13582,6 +13593,7 @@ function parseSkillsClient(value) {
|
|
|
13582
13593
|
|
|
13583
13594
|
export {
|
|
13584
13595
|
dashboardManagedRunKindsSchema,
|
|
13596
|
+
resolveOperatorApiKeyIds,
|
|
13585
13597
|
getBootstrapEnv,
|
|
13586
13598
|
isMachineFormat,
|
|
13587
13599
|
EXIT_USER_ERROR,
|