@canonry/canonry 5.6.0 → 5.9.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 (35) hide show
  1. package/assets/agent-workspace/skills/aero/SKILL.md +18 -0
  2. package/assets/agent-workspace/skills/aero/soul.md +2 -0
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +5 -4
  4. package/assets/assets/{AuditHistoryPanel-DVUbjx1M.js → AuditHistoryPanel-DumM4n44.js} +1 -1
  5. package/assets/assets/{BacklinksPage-D01VTDAp.js → BacklinksPage-DHW-aDYf.js} +1 -1
  6. package/assets/assets/{HistoryPage-Bk1gsXe5.js → HistoryPage-DJgCpcmY.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-D7p5vpY_.js → MeasurementPropertyPage-CblC7DUV.js} +1 -1
  8. package/assets/assets/{ProjectPage-Dv3USEIE.js → ProjectPage-BKZyG1S3.js} +1 -1
  9. package/assets/assets/{RunRow-Dpa0kAip.js → RunRow-plH2LI7o.js} +1 -1
  10. package/assets/assets/{RunsPage-B59z7DQ_.js → RunsPage-JCSy7P9I.js} +1 -1
  11. package/assets/assets/{SettingsPage-HJDgmQi9.js → SettingsPage-B8KXT4YK.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-BnJA-zvQ.js → SiteHealthSection-06pNjngi.js} +3 -3
  13. package/assets/assets/{TrafficPage-C8na59q_.js → TrafficPage-BYLDNQ1A.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-B2fO8bDc.js → TrafficSourceDetailPage-CxseBpYr.js} +1 -1
  15. package/assets/assets/{extract-error-message-670MySRM.js → extract-error-message-Dv5fwiqy.js} +1 -1
  16. package/assets/assets/index-2Ldc0Hq4.js +86 -0
  17. package/assets/assets/{index-PT4UiPTM.css → index-neNKCg78.css} +1 -1
  18. package/assets/assets/{react-sigma_core.esm.min-DOhuYLQj.js → react-sigma_core.esm.min-C8381RhL.js} +1 -1
  19. package/assets/assets/{v2-overview-adapter-CQyDNkXa.js → v2-overview-adapter-BQD1Ap8K.js} +1 -1
  20. package/assets/assets/vendor-markdown-B4giJcws.js +29 -0
  21. package/assets/index.html +3 -3
  22. package/dist/{chunk-TM2NQMJA.js → chunk-5E4ASNU4.js} +54 -7
  23. package/dist/{chunk-GHAUT7XJ.js → chunk-LR7BVM53.js} +1 -1
  24. package/dist/{chunk-KZYOJ4F5.js → chunk-R4COV5KR.js} +1 -1
  25. package/dist/{chunk-I4AHG7K3.js → chunk-S4DBS5DP.js} +1 -1
  26. package/dist/{chunk-C4KBR4H6.js → chunk-WTYVSCMP.js} +77 -22
  27. package/dist/cli.js +6 -6
  28. package/dist/{demo-server-JEGVGOPQ.js → demo-server-WRVVNKLS.js} +2 -2
  29. package/dist/index.d.ts +20 -8
  30. package/dist/index.js +4 -4
  31. package/dist/{intelligence-service-5P62KKG6.js → intelligence-service-4XMMO3JK.js} +1 -1
  32. package/dist/mcp.js +2 -2
  33. package/package.json +10 -10
  34. package/assets/assets/index-DTrkuKOh.js +0 -86
  35. package/assets/assets/vendor-markdown-B-Oq2NYq.js +0 -14
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-DTrkuKOh.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-2Ldc0Hq4.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-llkUFBGR.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-lucide-CneDbhOr.js">
20
- <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-B-Oq2NYq.js">
20
+ <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-B4giJcws.js">
21
21
  <link rel="modulepreload" crossorigin href="./assets/vendor-yaml-GWJz5H2G.js">
22
- <link rel="stylesheet" crossorigin href="./assets/index-PT4UiPTM.css">
22
+ <link rel="stylesheet" crossorigin href="./assets/index-neNKCg78.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="root"></div>
@@ -7406,6 +7406,26 @@ var MIGRATION_VERSIONS = [
7406
7406
  statements: [
7407
7407
  `ALTER TABLE doctor_health_state ADD COLUMN failing_signature TEXT`
7408
7408
  ]
7409
+ },
7410
+ {
7411
+ version: 158,
7412
+ name: "deepinfra-agent-default-model",
7413
+ // Move the previous agent default once. A later explicit GLM selection
7414
+ // must survive subsequent boots and session hydration.
7415
+ //
7416
+ // A run hook rather than a statement for two reasons. The statement
7417
+ // allowlist is schema-shaped and this rewrites VALUES, and a supported
7418
+ // legacy database can reach this version with no `agent_sessions` at
7419
+ // all: one stamped in `_migrations` at a version above 38 resumes past
7420
+ // the migration that introduces the table, so an unguarded UPDATE dies
7421
+ // with `no such table`.
7422
+ statements: [],
7423
+ run: (tx) => {
7424
+ if (!tableExists(tx, "agent_sessions")) return;
7425
+ tx.run(sql2.raw(
7426
+ `UPDATE agent_sessions SET model_id = 'deepseek-ai/DeepSeek-V4-Flash' WHERE model_provider = 'deepinfra' AND model_id = 'zai-org/GLM-5.2'`
7427
+ ));
7428
+ }
7409
7429
  }
7410
7430
  ];
7411
7431
  function addRunsMeasurementPlanVersionForeignKey(tx) {
@@ -11345,6 +11365,22 @@ function requireAdminSession(request) {
11345
11365
  if (!role || role === UserRoles.admin) return;
11346
11366
  throw forbidden(ADMIN_ONLY_MESSAGE);
11347
11367
  }
11368
+ var NARROW_KEY_DENIED_MESSAGE = "This API key is narrower than the install, so it cannot use an administrator surface.";
11369
+ function isInstanceAdministrator(request) {
11370
+ const principal = request.principal;
11371
+ if (!principal) return true;
11372
+ const role = principal.kind === "user" ? principal.role : principal.delegatedUser?.role;
11373
+ if (role && role !== UserRoles.admin) return false;
11374
+ return !principal.projectId && principal.scopes.includes(WILDCARD_SCOPE);
11375
+ }
11376
+ function requireInstanceAdministrator(request) {
11377
+ const principal = request.principal;
11378
+ if (!principal) return;
11379
+ const role = principal.kind === "user" ? principal.role : principal.delegatedUser?.role;
11380
+ if (role && role !== UserRoles.admin) throw forbidden(ADMIN_ONLY_MESSAGE);
11381
+ if (isInstanceAdministrator(request)) return;
11382
+ throw forbidden(NARROW_KEY_DENIED_MESSAGE);
11383
+ }
11348
11384
  function requireOperator(request) {
11349
11385
  const principal = request.principal;
11350
11386
  if (request.operatorAccess === true && principal?.kind === "api-key" && !principal.viaCookie && !principal.projectId && !principal.delegatedUser) return;
@@ -42637,7 +42673,7 @@ var canonryLocalRouteCatalog = [
42637
42673
  method: "get",
42638
42674
  path: "/api/v1/projects/{name}/agent/transcript",
42639
42675
  summary: "Get the rolling Aero transcript for this project",
42640
- description: "Returns the full message history of the project-scoped Aero session plus the persisted model provider/id and last-updated timestamp. Empty messages array when the project has no session yet.",
42676
+ description: "Returns the full message history of the project-scoped Aero session plus the persisted model provider/id and last-updated timestamp. Empty messages array when the project has no session yet. Administrator-only: a signed-in viewer, and any API key narrower than the install (read-only, or scoped to a single project), are refused with 403. There is one Aero session per project, so this is the operator conversation rather than metadata about it.",
42641
42677
  tags: ["agent"],
42642
42678
  parameters: [nameParameter],
42643
42679
  responses: {
@@ -42650,7 +42686,7 @@ var canonryLocalRouteCatalog = [
42650
42686
  method: "delete",
42651
42687
  path: "/api/v1/projects/{name}/agent/transcript",
42652
42688
  summary: "Reset the Aero transcript + queued follow-ups",
42653
- description: "Evicts any live Agent instance, clears the persisted messages and follow_up_queue. A subsequent prompt starts a fresh session.",
42689
+ description: "Evicts any live Agent instance, clears the persisted messages and follow_up_queue. A subsequent prompt starts a fresh session. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403.",
42654
42690
  tags: ["agent"],
42655
42691
  parameters: [nameParameter],
42656
42692
  responses: {
@@ -42663,7 +42699,7 @@ var canonryLocalRouteCatalog = [
42663
42699
  method: "get",
42664
42700
  path: "/api/v1/projects/{name}/agent/memory",
42665
42701
  summary: "List durable Aero memory entries for a project",
42666
- description: "Returns the project-scoped agent_memory rows newest-first. Includes both operator-authored notes (source `user`/`aero`) and LLM-authored compaction summaries (source `compaction`, key prefix `compaction:`). The N most-recent rows are also injected into the system prompt at every new session start.",
42702
+ description: "Returns the project-scoped agent_memory rows newest-first. Includes both operator-authored notes (source `user`/`aero`) and LLM-authored compaction summaries (source `compaction`, key prefix `compaction:`). The N most-recent rows are also injected into the system prompt at every new session start. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403.",
42667
42703
  tags: ["agent"],
42668
42704
  parameters: [nameParameter],
42669
42705
  responses: {
@@ -42676,7 +42712,7 @@ var canonryLocalRouteCatalog = [
42676
42712
  method: "put",
42677
42713
  path: "/api/v1/projects/{name}/agent/memory",
42678
42714
  summary: "Upsert a durable Aero memory entry",
42679
- description: "Creates or replaces a project-scoped note (max 2 KB, max 128-char key). Same key replaces the prior value. Keys with the reserved `compaction:` prefix are rejected \u2014 that namespace is owned by transcript compaction.",
42715
+ description: "Creates or replaces a project-scoped note (max 2 KB, max 128-char key). Same key replaces the prior value. Keys with the reserved `compaction:` prefix are rejected \u2014 that namespace is owned by transcript compaction. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403.",
42680
42716
  tags: ["agent"],
42681
42717
  parameters: [nameParameter],
42682
42718
  requestBody: {
@@ -42705,7 +42741,7 @@ var canonryLocalRouteCatalog = [
42705
42741
  method: "delete",
42706
42742
  path: "/api/v1/projects/{name}/agent/memory",
42707
42743
  summary: "Delete a durable Aero memory entry",
42708
- description: "Removes a single project-scoped note by key. Returns `status: missing` (non-error) when the key never existed. Keys with the reserved `compaction:` prefix are rejected \u2014 those notes are pruned automatically.",
42744
+ description: "Removes a single project-scoped note by key. Returns `status: missing` (non-error) when the key never existed. Keys with the reserved `compaction:` prefix are rejected \u2014 those notes are pruned automatically. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403.",
42709
42745
  tags: ["agent"],
42710
42746
  parameters: [nameParameter],
42711
42747
  requestBody: {
@@ -42733,7 +42769,7 @@ var canonryLocalRouteCatalog = [
42733
42769
  method: "get",
42734
42770
  path: "/api/v1/projects/{name}/agent/providers",
42735
42771
  summary: "List the LLM providers Aero can route to",
42736
- description: "Returns every provider Aero knows about with its default model, whether a usable API key is configured, and where the key resolved from (`config` | `env`). `defaultProvider` is the one Aero auto-picks when a caller omits `provider` on the prompt endpoint. Path is project-scoped for auth symmetry; the response does not vary per project today.",
42772
+ description: "Returns every provider Aero knows about with its default model, whether a usable API key is configured, and where the key resolved from (`config` | `env`). `defaultProvider` is the one Aero auto-picks when a caller omits `provider` on the prompt endpoint. Path is project-scoped for auth symmetry; the response does not vary per project today. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403, because each entry names a default model and which providers are configured is itself administrator knowledge.",
42737
42773
  tags: ["agent"],
42738
42774
  parameters: [nameParameter],
42739
42775
  responses: {
@@ -42745,7 +42781,7 @@ var canonryLocalRouteCatalog = [
42745
42781
  method: "post",
42746
42782
  path: "/api/v1/projects/{name}/agent/prompt",
42747
42783
  summary: "Send a prompt to Aero and stream events back as SSE",
42748
- description: 'Posts a prompt into the project\'s Aero session and streams `AgentEvent` frames as `text/event-stream`. Each frame is `data: <JSON>\\n\\n`. The server brackets the stream with `{"type":"stream_open"}` and `{"type":"stream_close"}` control frames; `{"type":"error","message":"..."}` surfaces in-stream failures without collapsing the stream. Returns 409 `AGENT_BUSY` if another turn is already in flight for this project. Body field `scope` accepts "all" | "read-only"; omitted defaults to "read-only" (safe dashboard surface). Body field `profile` accepts "default" | "ads-operator"; omitted keeps the default full Canonry operator surface. The CLI passes "all" to keep write tools available.',
42784
+ description: 'Posts a prompt into the project\'s Aero session and streams `AgentEvent` frames as `text/event-stream`. Each frame is `data: <JSON>\\n\\n`. The server brackets the stream with `{"type":"stream_open"}` and `{"type":"stream_close"}` control frames; `{"type":"error","message":"..."}` surfaces in-stream failures without collapsing the stream. Returns 409 `AGENT_BUSY` if another turn is already in flight for this project. Body field `scope` accepts "all" | "read-only"; omitted defaults to "read-only" (safe dashboard surface). Body field `profile` accepts "default" | "ads-operator"; omitted keeps the default full Canonry operator surface. The CLI passes "all" to keep write tools available. Administrator-only: a signed-in viewer, and any API key narrower than the install, are refused with 403. Tools execute with the install root key, so this route is an operator surface regardless of the scope requested.',
42749
42785
  tags: ["agent"],
42750
42786
  parameters: [nameParameter],
42751
42787
  requestBody: {
@@ -80704,6 +80740,14 @@ var agentProvidersConfiguredCheck = {
80704
80740
  scope: CheckScopes.global,
80705
80741
  title: "Agent provider keys",
80706
80742
  run: (ctx) => {
80743
+ if (ctx.callerIsInstanceAdministrator === false) {
80744
+ return {
80745
+ status: CheckStatuses.skipped,
80746
+ code: "agent-providers.restricted",
80747
+ summary: "Agent provider configuration is visible to administrators only.",
80748
+ remediation: null
80749
+ };
80750
+ }
80707
80751
  const summary2 = ctx.getAgentProviderSummary?.();
80708
80752
  if (!summary2) {
80709
80753
  return {
@@ -81970,6 +82014,7 @@ async function doctorRoutes(app, opts) {
81970
82014
  redirectUri,
81971
82015
  providerSummary: opts.providerSummary,
81972
82016
  getAgentProviderSummary: opts.getAgentProviderSummary,
82017
+ callerIsInstanceAdministrator: isInstanceAdministrator(request),
81973
82018
  trafficSourceValidators: opts.trafficSourceValidators,
81974
82019
  runtimeStatePaths: opts.runtimeStatePaths,
81975
82020
  bundledSkills: opts.bundledSkills,
@@ -82000,6 +82045,7 @@ async function doctorRoutes(app, opts) {
82000
82045
  redirectUri,
82001
82046
  providerSummary: opts.providerSummary,
82002
82047
  getAgentProviderSummary: opts.getAgentProviderSummary,
82048
+ callerIsInstanceAdministrator: isInstanceAdministrator(request),
82003
82049
  trafficSourceValidators: opts.trafficSourceValidators,
82004
82050
  runtimeStatePaths: opts.runtimeStatePaths,
82005
82051
  bundledSkills: opts.bundledSkills,
@@ -86753,6 +86799,7 @@ export {
86753
86799
  createUserSession,
86754
86800
  resolveUserSession,
86755
86801
  createCredentialChecker,
86802
+ requireInstanceAdministrator,
86756
86803
  hashApiKey,
86757
86804
  registerOAuthRoutes,
86758
86805
  registerOAuthAdminRoutes,
@@ -4,7 +4,7 @@ import {
4
4
  installSkills,
5
5
  loadConfigRaw,
6
6
  saveConfigPatch
7
- } from "./chunk-I4AHG7K3.js";
7
+ } from "./chunk-S4DBS5DP.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
10
  } from "./chunk-AOJU5LKX.js";
@@ -5,7 +5,7 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-TM2NQMJA.js";
8
+ } from "./chunk-5E4ASNU4.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
@@ -10041,7 +10041,7 @@ var canonryMcpTools = [
10041
10041
  defineTool({
10042
10042
  name: "canonry_project_overview",
10043
10043
  title: "Get project overview (composite)",
10044
- description: 'One-call summary for "how is project X doing?". Returns independent mention and citation coverage, separate query-level movement for each signal, query-basket comparability with added/removed counts, latest run and health, insights, provider/model breakdowns, competitors, attention items, and recent history. Movement excludes queries not shared by both sweeps. Filterable by location and time window. Prefer this over fanning out to separate tools.',
10044
+ description: 'One-call summary for "how is project X doing?". Returns independent mention and citation coverage, separate query-level movement for each signal, query-basket comparability with added/removed counts, latest run and health, insights, provider/model breakdowns, competitors, attention items, and recent history. Movement excludes queries not shared by both sweeps. Filterable by location and time window. Prefer this over fanning out to separate read tools for the same question. SCOPE LIMIT: this returns nothing about Advanced Measurement: no plan, Targets, Properties, groups, or segments. Its silence is not evidence that a project lacks them. Before stating that a project has no Properties, no Advanced plan, or cannot break out per-Property performance, call canonry_measurement_plan_get to establish the portfolio type, and canonry_measurement_portfolio_summary to rank Properties.',
10045
10045
  access: "read",
10046
10046
  tier: "core",
10047
10047
  inputSchema: z4.object({
@@ -16,12 +16,12 @@ import {
16
16
  resolveOperatorApiKeyIds,
17
17
  runWithUsageTags,
18
18
  saveConfigPatch
19
- } from "./chunk-I4AHG7K3.js";
19
+ } from "./chunk-S4DBS5DP.js";
20
20
  import {
21
21
  deleteSiteCrawlGraphLayout,
22
22
  persistSiteCrawlGraphLayout,
23
23
  prepareSiteCrawlGraphLayout
24
- } from "./chunk-KZYOJ4F5.js";
24
+ } from "./chunk-R4COV5KR.js";
25
25
  import {
26
26
  PACKAGE_VERSION
27
27
  } from "./chunk-AOJU5LKX.js";
@@ -152,6 +152,7 @@ import {
152
152
  refreshAccessToken,
153
153
  registerOAuthAdminRoutes,
154
154
  registerOAuthRoutes,
155
+ requireInstanceAdministrator,
155
156
  researchRunQueries,
156
157
  researchRuns,
157
158
  resolveDestination,
@@ -176,7 +177,7 @@ import {
176
177
  siteLivenessState,
177
178
  toAlertView,
178
179
  usageCounters
179
- } from "./chunk-TM2NQMJA.js";
180
+ } from "./chunk-5E4ASNU4.js";
180
181
  import {
181
182
  AGENT_MEMORY_VALUE_MAX_BYTES,
182
183
  AGENT_NONE,
@@ -6040,6 +6041,13 @@ function resolveAgentEnabled(env, config) {
6040
6041
  }
6041
6042
  return config.agent?.mode !== "disabled";
6042
6043
  }
6044
+ function resolveAgentProactiveEnabled(env, config) {
6045
+ const raw = env.CANONRY_AGENT_PROMPT_ONLY?.trim();
6046
+ if (raw) {
6047
+ return !(raw === "1" || raw.toLowerCase() === "true");
6048
+ }
6049
+ return config.agent?.mode !== "prompt-only";
6050
+ }
6043
6051
 
6044
6052
  // src/places-config.ts
6045
6053
  var DEFAULT_TIER = "atmosphere";
@@ -6468,7 +6476,7 @@ function nonBlank(value) {
6468
6476
  return trimmed ? trimmed : void 0;
6469
6477
  }
6470
6478
  function resolveBuildCommit(env = process.env) {
6471
- const embedded = true ? "f2d9ae1712b6aa64f5f6d4141c9a5208763a634e" : void 0;
6479
+ const embedded = true ? "3bdf995c7b38b778a35e91dc19377f788cc77204" : void 0;
6472
6480
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
6473
6481
  }
6474
6482
  function resolveInstanceIdentity(env = process.env) {
@@ -11762,7 +11770,7 @@ function readStoredGroundingSources(rawResponse) {
11762
11770
  return result;
11763
11771
  }
11764
11772
  async function backfillInsightsCommand(project, opts) {
11765
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-5P62KKG6.js");
11773
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-4XMMO3JK.js");
11766
11774
  const config = loadConfig();
11767
11775
  const db = createClient(config.database);
11768
11776
  migrate(db);
@@ -13656,11 +13664,18 @@ var PROVIDER_MODELS = {
13656
13664
  [LlmCapabilities.classify]: "glm-5-turbo"
13657
13665
  },
13658
13666
  [AgentProviderIds.deepinfra]: {
13659
- // DeepInfra `org/Model` slugs. GLM-5.2 (Sonnet-class) on all three tiers —
13660
- // it undercuts the Claude tiers it replaces, so the cheaper tiers take no
13661
- // quality hit. Resolved into a custom openai-completions model, not pi-ai's
13662
- // catalog.
13663
- [LlmCapabilities.agent]: "zai-org/GLM-5.2",
13667
+ // DeepInfra `org/Model` slugs, resolved into a custom openai-completions
13668
+ // model rather than pi-ai's catalog.
13669
+ //
13670
+ // The agent tier is pinned explicitly: the dashboard picker sends a
13671
+ // provider and no model, so whatever sits here is what selecting DeepInfra
13672
+ // pins a session to.
13673
+ //
13674
+ // analyze + classify stay on GLM on purpose. Those tiers suppress the
13675
+ // reasoning trace through GLM's chat-template switch, and that branch
13676
+ // applies only to a model declared `reasoning: true`; moving them to
13677
+ // DeepSeek-V4-Flash (which is not) would quietly stop suppressing anything.
13678
+ [LlmCapabilities.agent]: "deepseek-ai/DeepSeek-V4-Flash",
13664
13679
  [LlmCapabilities.analyze]: "zai-org/GLM-5.2",
13665
13680
  [LlmCapabilities.classify]: "zai-org/GLM-5.2"
13666
13681
  }
@@ -13718,7 +13733,7 @@ var AGENT_PROVIDERS = {
13718
13733
  },
13719
13734
  // Best-effort metadata. Costs are USD/1M tokens (DeepInfra published
13720
13735
  // rates: GLM-5.2 ~$0.95 in / $0.18 cached / $3.00 out; DeepSeek-V4-Flash
13721
- // ~$0.10 in / $0.20 out). contextWindow is DeepInfra's 1M (fp4) serving
13736
+ // $0.09 in / $0.18 out). contextWindow is DeepInfra's 1M (fp4) serving
13722
13737
  // window for both models; it's descriptive (see OpenAiCompatibleModelMeta),
13723
13738
  // so it documents the real window rather than gating compaction.
13724
13739
  knownModels: {
@@ -13732,7 +13747,7 @@ var AGENT_PROVIDERS = {
13732
13747
  contextWindow: 1048576,
13733
13748
  maxTokens: 32768,
13734
13749
  reasoning: false,
13735
- cost: { input: 0.1, output: 0.2, cacheRead: 0, cacheWrite: 0 }
13750
+ cost: { input: 0.09, output: 0.18, cacheRead: 0, cacheWrite: 0 }
13736
13751
  }
13737
13752
  },
13738
13753
  // Fallback for arbitrary `--model` slugs we don't ship as tiers. cost is
@@ -13981,6 +13996,8 @@ import { Type as Type2 } from "@sinclair/typebox";
13981
13996
  import { randomUUID } from "crypto";
13982
13997
  var MAX_TOOL_RESULT_CHARS = 2e4;
13983
13998
  var TRUNCATION_NOTE = "... (truncated \u2014 result too large)";
13999
+ var MAX_STRUCTURED_TRUNCATION_CHARS = 2e6;
14000
+ var MAX_TRUNCATION_PASSES = 32;
13984
14001
  function serializeResult(value) {
13985
14002
  return JSON.stringify(value, null, 2);
13986
14003
  }
@@ -13998,11 +14015,17 @@ function largestArrayKey(obj) {
13998
14015
  return best;
13999
14016
  }
14000
14017
  function trimRowsToFit(rows, render) {
14001
- let kept = rows.slice();
14002
- while (kept.length > 0 && render(kept).length > MAX_TOOL_RESULT_CHARS) {
14003
- kept = kept.slice(0, -1);
14004
- }
14005
- return kept;
14018
+ if (rows.length === 0) return [];
14019
+ const all = rows.slice();
14020
+ if (render(all).length <= MAX_TOOL_RESULT_CHARS) return all;
14021
+ let low = 0;
14022
+ let high = rows.length - 1;
14023
+ while (low < high) {
14024
+ const middle = Math.ceil((low + high) / 2);
14025
+ if (render(rows.slice(0, middle)).length <= MAX_TOOL_RESULT_CHARS) low = middle;
14026
+ else high = middle - 1;
14027
+ }
14028
+ return rows.slice(0, low);
14006
14029
  }
14007
14030
  function nestedArrayCandidates(root) {
14008
14031
  const candidates = [];
@@ -14039,7 +14062,9 @@ function trimNestedArrays(full) {
14039
14062
  const copy = parsed;
14040
14063
  copy.__truncated = true;
14041
14064
  let out = serializeResult(copy);
14065
+ let passes = 0;
14042
14066
  while (out.length > MAX_TOOL_RESULT_CHARS) {
14067
+ if (++passes > MAX_TRUNCATION_PASSES) return void 0;
14043
14068
  const candidate = nestedArrayCandidates(copy).at(0);
14044
14069
  if (!candidate) return void 0;
14045
14070
  const { owner, key, rows } = candidate;
@@ -14069,6 +14094,9 @@ function trimNestedArrays(full) {
14069
14094
  function truncateToolResult(details) {
14070
14095
  const full = serializeResult(details);
14071
14096
  if (full.length <= MAX_TOOL_RESULT_CHARS) return full;
14097
+ if (full.length > MAX_STRUCTURED_TRUNCATION_CHARS) {
14098
+ return full.slice(0, MAX_TOOL_RESULT_CHARS) + "\n" + TRUNCATION_NOTE;
14099
+ }
14072
14100
  if (Array.isArray(details)) {
14073
14101
  const kept = trimRowsToFit(
14074
14102
  details,
@@ -15038,6 +15066,15 @@ var MAX_HYDRATE_BYTES = 32 * 1024;
15038
15066
  function escapeMemoryFragment(value) {
15039
15067
  return value.replace(/<(\/?)memory>/gi, "<$1\u200Cmemory>");
15040
15068
  }
15069
+ function withoutPersistedToolDetails(messages) {
15070
+ return messages.map((message) => {
15071
+ if (!message || typeof message !== "object") return message;
15072
+ const row = message;
15073
+ if (row.role !== "toolResult" || !("details" in row)) return message;
15074
+ const { details: _omitted, ...rest } = row;
15075
+ return rest;
15076
+ });
15077
+ }
15041
15078
  var SessionRegistry = class {
15042
15079
  live = /* @__PURE__ */ new Map();
15043
15080
  pending = /* @__PURE__ */ new Map();
@@ -15065,6 +15102,10 @@ var SessionRegistry = class {
15065
15102
  constructor(opts) {
15066
15103
  this.opts = opts;
15067
15104
  }
15105
+ /** False only in prompt-only mode; absent means proactive, as it always was. */
15106
+ get proactive() {
15107
+ return this.opts.proactive !== false;
15108
+ }
15068
15109
  /**
15069
15110
  * Lazily load + cache the injected remote MCP tools. The seam OSS-A exposes:
15070
15111
  * `loadExternalMcpTools` connects to each configured server over the frozen
@@ -15149,7 +15190,7 @@ var SessionRegistry = class {
15149
15190
  this.scopes.set(projectName, preferences?.toolScope ?? AeroToolScopes.all);
15150
15191
  this.profiles.set(projectName, preferences?.toolProfile ?? AeroToolProfiles.default);
15151
15192
  this.projectIds.set(projectName, projectId);
15152
- if (queued.length > 0) {
15193
+ if (queued.length > 0 && this.proactive) {
15153
15194
  this.appendPending(projectName, queued);
15154
15195
  this.updateRow(projectId, { followUpQueue: "[]" });
15155
15196
  }
@@ -15378,7 +15419,7 @@ ${lines.join("\n")}
15378
15419
  if (!agent) return;
15379
15420
  const projectId = this.resolveProjectId(projectName);
15380
15421
  this.updateRow(projectId, {
15381
- messages: JSON.stringify(agent.state.messages)
15422
+ messages: JSON.stringify(withoutPersistedToolDetails(agent.state.messages))
15382
15423
  });
15383
15424
  }
15384
15425
  /**
@@ -15395,6 +15436,7 @@ ${lines.join("\n")}
15395
15436
  * both the in-memory pending and the DB-queue migration produced copies).
15396
15437
  */
15397
15438
  queueFollowUp(projectName, message) {
15439
+ if (!this.proactive) return;
15398
15440
  if (this.live.has(projectName)) {
15399
15441
  this.appendPending(projectName, [message]);
15400
15442
  } else {
@@ -15403,6 +15445,7 @@ ${lines.join("\n")}
15403
15445
  }
15404
15446
  /** Consume (and clear) the pending queue for a project. Caller prompts with the result. */
15405
15447
  consumePending(projectName) {
15448
+ if (!this.proactive) return [];
15406
15449
  const msgs = this.pending.get(projectName) ?? [];
15407
15450
  if (msgs.length === 0) return [];
15408
15451
  this.pending.delete(projectName);
@@ -15422,6 +15465,7 @@ ${lines.join("\n")}
15422
15465
  * RunCoordinator calls after a run completes to wake Aero unprompted.
15423
15466
  */
15424
15467
  async drainNow(projectName) {
15468
+ if (!this.proactive) return;
15425
15469
  if (!this.hasPendingWork(projectName)) return;
15426
15470
  try {
15427
15471
  let agent;
@@ -15549,7 +15593,7 @@ ${lines.join("\n")}
15549
15593
  systemPrompt: params.systemPrompt,
15550
15594
  modelProvider: params.provider ?? params.modelProvider ?? AgentProviderIds.claude,
15551
15595
  modelId: params.modelId ?? "claude-opus-4-7",
15552
- messages: JSON.stringify(params.messages),
15596
+ messages: JSON.stringify(withoutPersistedToolDetails(params.messages)),
15553
15597
  followUpQueue: JSON.stringify(params.followUpQueue),
15554
15598
  createdAt: now,
15555
15599
  updatedAt: now
@@ -15786,13 +15830,15 @@ function registerAgentRoutes(app, opts) {
15786
15830
  app.get(
15787
15831
  "/projects/:name/agent/transcript",
15788
15832
  async (request) => {
15833
+ requireInstanceAdministrator(request);
15789
15834
  const project = resolveProject(opts.db, request.params.name);
15790
15835
  const row = opts.db.select().from(agentSessions).where(eq22(agentSessions.projectId, project.id)).get();
15791
15836
  if (!row) {
15792
15837
  return { messages: [], modelProvider: null, modelId: null, updatedAt: null };
15793
15838
  }
15839
+ const messages = parseJsonColumn(row.messages, []);
15794
15840
  return {
15795
- messages: parseJsonColumn(row.messages, []),
15841
+ messages,
15796
15842
  modelProvider: row.modelProvider,
15797
15843
  modelId: row.modelId,
15798
15844
  updatedAt: row.updatedAt
@@ -15802,6 +15848,7 @@ function registerAgentRoutes(app, opts) {
15802
15848
  app.get(
15803
15849
  "/projects/:name/agent/providers",
15804
15850
  async (request) => {
15851
+ requireInstanceAdministrator(request);
15805
15852
  resolveProject(opts.db, request.params.name);
15806
15853
  return buildAgentProvidersResponse(opts.sessionRegistry.getConfig());
15807
15854
  }
@@ -15809,6 +15856,7 @@ function registerAgentRoutes(app, opts) {
15809
15856
  app.delete(
15810
15857
  "/projects/:name/agent/transcript",
15811
15858
  async (request) => {
15859
+ requireInstanceAdministrator(request);
15812
15860
  const project = resolveProject(opts.db, request.params.name);
15813
15861
  opts.sessionRegistry.reset(project.name);
15814
15862
  opts.db.update(agentSessions).set({ messages: "[]", followUpQueue: "[]", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq22(agentSessions.projectId, project.id)).run();
@@ -15816,6 +15864,7 @@ function registerAgentRoutes(app, opts) {
15816
15864
  }
15817
15865
  );
15818
15866
  app.post("/projects/:name/agent/prompt", async (request, reply) => {
15867
+ requireInstanceAdministrator(request);
15819
15868
  const project = resolveProject(opts.db, request.params.name);
15820
15869
  const body = request.body;
15821
15870
  const promptText = (body?.prompt ?? "").trim();
@@ -15877,6 +15926,7 @@ function registerAgentRoutes(app, opts) {
15877
15926
  app.get(
15878
15927
  "/projects/:name/agent/memory",
15879
15928
  async (request) => {
15929
+ requireInstanceAdministrator(request);
15880
15930
  const project = resolveProject(opts.db, request.params.name);
15881
15931
  return { entries: listMemoryEntries(opts.db, project.id) };
15882
15932
  }
@@ -15884,6 +15934,7 @@ function registerAgentRoutes(app, opts) {
15884
15934
  app.put(
15885
15935
  "/projects/:name/agent/memory",
15886
15936
  async (request) => {
15937
+ requireInstanceAdministrator(request);
15887
15938
  const project = resolveProject(opts.db, request.params.name);
15888
15939
  const parsed = agentMemoryUpsertRequestSchema.safeParse(request.body);
15889
15940
  if (!parsed.success) {
@@ -15910,6 +15961,7 @@ function registerAgentRoutes(app, opts) {
15910
15961
  app.delete(
15911
15962
  "/projects/:name/agent/memory",
15912
15963
  async (request) => {
15964
+ requireInstanceAdministrator(request);
15913
15965
  const project = resolveProject(opts.db, request.params.name);
15914
15966
  const parsed = agentMemoryDeleteRequestSchema.safeParse(request.body);
15915
15967
  if (!parsed.success) {
@@ -17597,10 +17649,12 @@ async function createServer(opts) {
17597
17649
  skipProbe: true
17598
17650
  });
17599
17651
  const agentEnabled = resolveAgentEnabled(process.env, opts.config);
17652
+ const agentProactive = resolveAgentProactiveEnabled(process.env, opts.config);
17600
17653
  const sessionRegistry = agentEnabled ? new SessionRegistry({
17601
17654
  db: opts.db,
17602
17655
  client: aeroClient,
17603
- config: opts.config
17656
+ config: opts.config,
17657
+ proactive: agentProactive
17604
17658
  }) : void 0;
17605
17659
  const runCoordinator = new RunCoordinator(
17606
17660
  opts.db,
@@ -17609,6 +17663,7 @@ async function createServer(opts) {
17609
17663
  (runId, projectId, result) => notifier.dispatchInsightWebhooks(runId, projectId, result),
17610
17664
  async (ctx) => {
17611
17665
  if (!sessionRegistry) return;
17666
+ if (!agentProactive) return;
17612
17667
  const project = opts.db.select({ name: projects.name }).from(projects).where(eq25(projects.id, ctx.projectId)).get();
17613
17668
  if (!project) return;
17614
17669
  let content;
package/dist/cli.js CHANGED
@@ -35,11 +35,11 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-C4KBR4H6.js";
38
+ } from "./chunk-WTYVSCMP.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-GHAUT7XJ.js";
42
+ } from "./chunk-LR7BVM53.js";
43
43
  import {
44
44
  CliError,
45
45
  EXIT_SYSTEM_ERROR,
@@ -66,13 +66,13 @@ import {
66
66
  shouldPrintServeSkillsNudge,
67
67
  systemError,
68
68
  usageError
69
- } from "./chunk-I4AHG7K3.js";
69
+ } from "./chunk-S4DBS5DP.js";
70
70
  import {
71
71
  DEFAULT_DEMO_TRUSTED_PROXIES,
72
72
  trustedProxiesProblem,
73
73
  trustedProxyProblem
74
74
  } from "./chunk-RB2F4D3Z.js";
75
- import "./chunk-KZYOJ4F5.js";
75
+ import "./chunk-R4COV5KR.js";
76
76
  import "./chunk-AOJU5LKX.js";
77
77
  import {
78
78
  CLOUDFLARE_WORKER_BINDINGS,
@@ -88,7 +88,7 @@ import {
88
88
  queries,
89
89
  renderReportHtml,
90
90
  runs
91
- } from "./chunk-TM2NQMJA.js";
91
+ } from "./chunk-5E4ASNU4.js";
92
92
  import {
93
93
  AdsDeliverySnapshotStatuses,
94
94
  AdsHistoricalCampaignRollupStatuses,
@@ -435,7 +435,7 @@ function parseDemoTrustedProxies(values) {
435
435
  async function demoCommand(options) {
436
436
  const { host, port } = parseDemoListenOptions(options);
437
437
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
438
- const { createDemoServer } = await import("./demo-server-JEGVGOPQ.js");
438
+ const { createDemoServer } = await import("./demo-server-WRVVNKLS.js");
439
439
  const app = await createDemoServer({ trustProxy });
440
440
  let stopping = false;
441
441
  const stop = () => {
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  layoutSiteCrawlGraphInput,
6
6
  persistSiteCrawlGraphLayout
7
- } from "./chunk-KZYOJ4F5.js";
7
+ } from "./chunk-R4COV5KR.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
10
  } from "./chunk-AOJU5LKX.js";
@@ -83,7 +83,7 @@ import {
83
83
  siteCrawlPages,
84
84
  siteCrawlSnapshots,
85
85
  trafficSources
86
- } from "./chunk-TM2NQMJA.js";
86
+ } from "./chunk-5E4ASNU4.js";
87
87
  import {
88
88
  RunKinds,
89
89
  SiteCrawlFetchStates,
package/dist/index.d.ts CHANGED
@@ -268,15 +268,27 @@ interface ExternalMcpServerConfig {
268
268
  }
269
269
  interface AgentConfigEntry {
270
270
  /**
271
- * Agent mode. `'disabled'` turns the built-in Aero agent OFF entirely — the
272
- * proactive auto-wake on run completion does not fire, the `SessionRegistry`
273
- * is not constructed, and the interactive agent routes (`/projects/:name/
274
- * agent/*`) plus the `canonry agent ask` CLI (a thin client of those routes)
275
- * are not served. Absent (the default) leaves Aero enabled. Resolved, with
276
- * the `CANONRY_AGENT_DISABLED` env override, by `resolveAgentEnabled` in
277
- * agent-config.ts.
271
+ * Agent mode. Three states, held on ONE field so they stay mutually
272
+ * exclusive: there is no way to write down "off, but still waking itself".
273
+ *
274
+ * - `'disabled'` turns the built-in Aero agent OFF entirely — the proactive
275
+ * auto-wake on run completion does not fire, the `SessionRegistry` is not
276
+ * constructed, and the interactive agent routes (`/projects/:name/agent/*`)
277
+ * plus the `canonry agent ask` CLI (a thin client of those routes) are not
278
+ * served. Resolved, with the `CANONRY_AGENT_DISABLED` env override, by
279
+ * `resolveAgentEnabled`.
280
+ * - `'prompt-only'` keeps every interactive surface and removes ONLY the
281
+ * proactive wake: Aero answers when asked and never starts a turn by
282
+ * itself, so it costs nothing while nobody is talking to it and never
283
+ * writes into the transcript unattended. Resolved, with the
284
+ * `CANONRY_AGENT_PROMPT_ONLY` env override, by
285
+ * `resolveAgentProactiveEnabled`.
286
+ * - absent (the default) leaves Aero enabled AND proactive, which is the
287
+ * behaviour every existing install already has.
288
+ *
289
+ * Both resolvers live in agent-config.ts.
278
290
  */
279
- mode?: 'disabled';
291
+ mode?: 'disabled' | 'prompt-only';
280
292
  }
281
293
  interface DashboardConfigEntry {
282
294
  /**
package/dist/index.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-C4KBR4H6.js";
6
+ } from "./chunk-WTYVSCMP.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-I4AHG7K3.js";
10
- import "./chunk-KZYOJ4F5.js";
9
+ } from "./chunk-S4DBS5DP.js";
10
+ import "./chunk-R4COV5KR.js";
11
11
  import "./chunk-AOJU5LKX.js";
12
- import "./chunk-TM2NQMJA.js";
12
+ import "./chunk-5E4ASNU4.js";
13
13
  import "./chunk-D3DKDTXP.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-TM2NQMJA.js";
4
+ } from "./chunk-5E4ASNU4.js";
5
5
  import "./chunk-D3DKDTXP.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,