@canonry/canonry 4.167.1 → 4.168.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.
@@ -1,16 +1,15 @@
1
1
  import {
2
2
  ApiClient,
3
3
  CanonryMcpToolNames,
4
- CliError,
5
- PACKAGE_VERSION,
6
4
  canonryMcpTools,
7
5
  configExists,
6
+ getBundledSkillSnapshots,
8
7
  getConfigPath,
9
8
  isMachineFormat,
10
9
  loadConfig,
11
10
  loadConfigRaw,
12
11
  saveConfigPatch
13
- } from "./chunk-P5LR3NDQ.js";
12
+ } from "./chunk-C4UWZLQX.js";
14
13
  import {
15
14
  CC_CACHE_DIR,
16
15
  DUCKDB_SPEC,
@@ -139,7 +138,7 @@ import {
139
138
  siteCrawlSnapshots,
140
139
  toAlertView,
141
140
  usageCounters
142
- } from "./chunk-7M3QVRJD.js";
141
+ } from "./chunk-CDACTPTY.js";
143
142
  import {
144
143
  AGENT_MEMORY_VALUE_MAX_BYTES,
145
144
  AGENT_PROVIDER_IDS,
@@ -151,7 +150,6 @@ import {
151
150
  BacklinkSources,
152
151
  CITED_URL_CAPTURE_VERSION,
153
152
  CcReleaseSyncStatuses,
154
- CodingAgents,
155
153
  DiscoveryCompetitorTypes,
156
154
  LLM_CAPABILITIES,
157
155
  LlmCapabilities,
@@ -170,10 +168,8 @@ import {
170
168
  SITE_AUDIT_MAX_PAGE_LIMIT,
171
169
  SITE_CRAWL_GRAPH_MAX_EDGES,
172
170
  SITE_CRAWL_GRAPH_MAX_NODES,
173
- SKILL_MANIFEST_FILENAME,
174
171
  SchedulableRunKinds,
175
172
  SiteHealthLinkClassificationSources,
176
- SkillsClients,
177
173
  TEMPLATE_LINK_RATIO_THRESHOLD,
178
174
  TrafficEventConfidences,
179
175
  TrafficEventKinds,
@@ -192,10 +188,8 @@ import {
192
188
  authRequired,
193
189
  bucketOnboardingCount,
194
190
  buildRunErrorFromMessages,
195
- classifySkillFile,
196
191
  classifyTemplateLinkEdge,
197
192
  cloudflareQueueNameSchema,
198
- coerceSkillManifest,
199
193
  computeBacklinkSummaryMetrics,
200
194
  contentActionLabel,
201
195
  contentBriefDtoSchema,
@@ -243,7 +237,6 @@ import {
243
237
  serializeRunError,
244
238
  shiftIsoCalendarDate,
245
239
  siteAuditRequestIdentity,
246
- skillsClientSchema,
247
240
  splitList,
248
241
  startOfDayHourInTimeZone,
249
242
  templateLinkDetection,
@@ -585,13 +578,13 @@ function checkLatestVersionForServer(opts) {
585
578
 
586
579
  // src/server.ts
587
580
  import { createRequire as createRequire4 } from "module";
588
- import crypto25 from "crypto";
589
- import fs8 from "fs";
590
- import path9 from "path";
591
- import { fileURLToPath as fileURLToPath3 } from "url";
581
+ import crypto24 from "crypto";
582
+ import fs7 from "fs";
583
+ import path8 from "path";
584
+ import { fileURLToPath as fileURLToPath2 } from "url";
592
585
  import { and as and18, eq as eq24 } from "drizzle-orm";
593
586
  import Fastify from "fastify";
594
- import os5 from "os";
587
+ import os4 from "os";
595
588
 
596
589
  // ../provider-gemini/src/normalize.ts
597
590
  import { GoogleGenAI } from "@google/genai";
@@ -5181,12 +5174,12 @@ function adsClientLog(level, action, ctx) {
5181
5174
  const stream = level === "error" ? process.stderr : process.stdout;
5182
5175
  stream.write(JSON.stringify(entry) + "\n");
5183
5176
  }
5184
- function buildUrl(path10, queryPairs) {
5177
+ function buildUrl(path9, queryPairs) {
5185
5178
  const qs = queryPairs.join("&");
5186
- return qs ? `${OPENAI_ADS_API_BASE}/${path10}?${qs}` : `${OPENAI_ADS_API_BASE}/${path10}`;
5179
+ return qs ? `${OPENAI_ADS_API_BASE}/${path9}?${qs}` : `${OPENAI_ADS_API_BASE}/${path9}`;
5187
5180
  }
5188
- async function adsFetch(apiKey, path10, queryPairs = [], method = "GET", body) {
5189
- const url = buildUrl(path10, queryPairs);
5181
+ async function adsFetch(apiKey, path9, queryPairs = [], method = "GET", body) {
5182
+ const url = buildUrl(path9, queryPairs);
5190
5183
  const res = await fetch(url, {
5191
5184
  method,
5192
5185
  headers: {
@@ -5198,18 +5191,18 @@ async function adsFetch(apiKey, path10, queryPairs = [], method = "GET", body) {
5198
5191
  });
5199
5192
  if (res.status === 401 || res.status === 403) {
5200
5193
  const { code } = parseErrorEnvelope(await res.text());
5201
- adsClientLog("error", "http.auth-failed", { path: path10, httpStatus: res.status, code });
5194
+ adsClientLog("error", "http.auth-failed", { path: path9, httpStatus: res.status, code });
5202
5195
  throw new OpenAiAdsApiError("OpenAI Ads API key is invalid or unauthorized", res.status, code);
5203
5196
  }
5204
5197
  if (res.status === 429) {
5205
5198
  const { code } = parseErrorEnvelope(await res.text());
5206
- adsClientLog("error", "http.rate-limited", { path: path10, httpStatus: 429, code });
5199
+ adsClientLog("error", "http.rate-limited", { path: path9, httpStatus: 429, code });
5207
5200
  throw new OpenAiAdsApiError("OpenAI Ads API rate limit exceeded", 429, code);
5208
5201
  }
5209
5202
  if (!res.ok) {
5210
5203
  const body2 = await res.text();
5211
5204
  const { message, code } = parseErrorEnvelope(body2);
5212
- adsClientLog("error", "http.error", { path: path10, httpStatus: res.status, code });
5205
+ adsClientLog("error", "http.error", { path: path9, httpStatus: res.status, code });
5213
5206
  const detail = message ?? (body2.length <= 500 ? body2 : `${body2.slice(0, 500)}... [truncated]`);
5214
5207
  throw new OpenAiAdsApiError(`OpenAI Ads API error (${res.status}): ${detail}`, res.status, code);
5215
5208
  }
@@ -5220,12 +5213,12 @@ async function adsFetch(apiKey, path10, queryPairs = [], method = "GET", body) {
5220
5213
  throw new OpenAiAdsApiError("OpenAI Ads API returned invalid JSON", 502);
5221
5214
  }
5222
5215
  }
5223
- async function fetchAllPages(apiKey, path10, queryPairs, maxPages = OPENAI_ADS_MAX_PAGES) {
5216
+ async function fetchAllPages(apiKey, path9, queryPairs, maxPages = OPENAI_ADS_MAX_PAGES) {
5224
5217
  const items = [];
5225
5218
  let after = null;
5226
5219
  for (let page = 0; page < maxPages; page++) {
5227
5220
  const pairs = after ? [...queryPairs, `after=${encodeURIComponent(after)}`] : [...queryPairs];
5228
- const response = await adsFetch(apiKey, path10, pairs);
5221
+ const response = await adsFetch(apiKey, path9, pairs);
5229
5222
  items.push(...response.data);
5230
5223
  if (!response.has_more || !response.last_id) {
5231
5224
  return items;
@@ -5233,7 +5226,7 @@ async function fetchAllPages(apiKey, path10, queryPairs, maxPages = OPENAI_ADS_M
5233
5226
  after = response.last_id;
5234
5227
  }
5235
5228
  if (maxPages < OPENAI_ADS_MAX_PAGES) return items;
5236
- adsClientLog("error", "pagination.cap-reached", { path: path10, pages: OPENAI_ADS_MAX_PAGES, items: items.length });
5229
+ adsClientLog("error", "pagination.cap-reached", { path: path9, pages: OPENAI_ADS_MAX_PAGES, items: items.length });
5237
5230
  throw new OpenAiAdsApiError(
5238
5231
  `OpenAI Ads API collection remained incomplete after the ${OPENAI_ADS_MAX_PAGES}-page safety cap`,
5239
5232
  502,
@@ -7394,8 +7387,8 @@ function hashUnit(value) {
7394
7387
  }
7395
7388
  return (hash >>> 0) / 4294967296;
7396
7389
  }
7397
- function pathSection(path10) {
7398
- return path10.split("/").filter(Boolean)[0] ?? "__root__";
7390
+ function pathSection(path9) {
7391
+ return path9.split("/").filter(Boolean)[0] ?? "__root__";
7399
7392
  }
7400
7393
  function seedSiteCrawlGraphNodes(nodes, rootNodeKey, priorPositions) {
7401
7394
  return [...nodes].sort((a, b) => a.sampleRank - b.sampleRank || a.nodeKey.localeCompare(b.nodeKey)).map((node) => {
@@ -8026,9 +8019,9 @@ function pagePath(page) {
8026
8019
  }
8027
8020
  }
8028
8021
  function parentPath(page) {
8029
- const path10 = pagePath(page);
8030
- if (path10 === "/") return "/";
8031
- const trimmed = path10.endsWith("/") ? path10.slice(0, -1) : path10;
8022
+ const path9 = pagePath(page);
8023
+ if (path9 === "/") return "/";
8024
+ const trimmed = path9.endsWith("/") ? path9.slice(0, -1) : path9;
8032
8025
  const slash = trimmed.lastIndexOf("/");
8033
8026
  return slash <= 0 ? "/" : trimmed.slice(0, slash) || "/";
8034
8027
  }
@@ -9094,7 +9087,7 @@ function readStoredGroundingSources(rawResponse) {
9094
9087
  return result;
9095
9088
  }
9096
9089
  async function backfillInsightsCommand(project, opts) {
9097
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-ULDOVV5Y.js");
9090
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-KBSDKHED.js");
9098
9091
  const config = loadConfig();
9099
9092
  const db = createClient(config.database);
9100
9093
  migrate(db);
@@ -9618,352 +9611,6 @@ No DB writes performed. Re-run without --dry-run to apply.`);
9618
9611
  }
9619
9612
  }
9620
9613
 
9621
- // src/commands/skills.ts
9622
- import crypto18 from "crypto";
9623
- import fs4 from "fs";
9624
- import os4 from "os";
9625
- import path5 from "path";
9626
- import { fileURLToPath } from "url";
9627
- var BUNDLED_SKILL_NAMES = ["canonry", "aero"];
9628
- function resolveBundledSkillsRoot(pkgDir) {
9629
- const here = pkgDir ?? path5.dirname(fileURLToPath(import.meta.url));
9630
- const candidates = [
9631
- path5.join(here, "../assets/agent-workspace/skills"),
9632
- path5.join(here, "../../assets/agent-workspace/skills"),
9633
- path5.join(here, "../../../../skills")
9634
- ];
9635
- for (const candidate of candidates) {
9636
- if (BUNDLED_SKILL_NAMES.every((name) => fs4.existsSync(path5.join(candidate, name, "SKILL.md")))) {
9637
- return candidate;
9638
- }
9639
- }
9640
- throw new CliError({
9641
- code: "INTERNAL_ERROR",
9642
- message: `Bundled skills not found. Searched:
9643
- ${candidates.join("\n ")}`,
9644
- exitCode: 2
9645
- });
9646
- }
9647
- function parseDescription(content) {
9648
- const fmMatch = /^---\n([\s\S]*?)\n---/.exec(content);
9649
- if (!fmMatch) return "";
9650
- const descMatch = /^description:\s*(\S.*)$/m.exec(fmMatch[1]);
9651
- if (!descMatch) return "";
9652
- return descMatch[1].replace(/^["']|["']$/g, "").trim();
9653
- }
9654
- function getBundledSkills(pkgDir) {
9655
- const root = resolveBundledSkillsRoot(pkgDir);
9656
- return BUNDLED_SKILL_NAMES.map((name) => {
9657
- const skillDir = path5.join(root, name);
9658
- const skillFile = path5.join(skillDir, "SKILL.md");
9659
- const content = fs4.readFileSync(skillFile, "utf-8");
9660
- return { name, description: parseDescription(content), bundledPath: skillDir };
9661
- });
9662
- }
9663
- function walkRelative(dir, prefix = "") {
9664
- const out = [];
9665
- for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
9666
- const rel = prefix ? path5.join(prefix, entry.name) : entry.name;
9667
- const full = path5.join(dir, entry.name);
9668
- if (entry.isDirectory()) {
9669
- out.push(...walkRelative(full, rel));
9670
- } else if (entry.isFile()) {
9671
- out.push(rel);
9672
- }
9673
- }
9674
- return out.sort();
9675
- }
9676
- function sha256File(filePath) {
9677
- return crypto18.createHash("sha256").update(fs4.readFileSync(filePath)).digest("hex");
9678
- }
9679
- function readSkillManifest(skillDir) {
9680
- try {
9681
- return coerceSkillManifest(JSON.parse(fs4.readFileSync(path5.join(skillDir, SKILL_MANIFEST_FILENAME), "utf-8")));
9682
- } catch {
9683
- return null;
9684
- }
9685
- }
9686
- function writeSkillManifest(skillDir, manifest) {
9687
- fs4.writeFileSync(path5.join(skillDir, SKILL_MANIFEST_FILENAME), `${JSON.stringify(manifest, null, 2)}
9688
- `, "utf-8");
9689
- }
9690
- function reconcileSkillTree(srcDir, destDir, manifest, force) {
9691
- const result = { added: [], updated: [], unchanged: [], conflicts: [], bundledHashes: /* @__PURE__ */ new Map() };
9692
- for (const rel of walkRelative(srcDir)) {
9693
- const srcPath = path5.join(srcDir, rel);
9694
- const destPath = path5.join(destDir, rel);
9695
- const bundledHash = sha256File(srcPath);
9696
- result.bundledHashes.set(rel, bundledHash);
9697
- const installedHash = fs4.existsSync(destPath) ? sha256File(destPath) : void 0;
9698
- const state = classifySkillFile({ bundledHash, installedHash, manifestHash: manifest?.files[rel] });
9699
- switch (state) {
9700
- case "missing":
9701
- fs4.mkdirSync(path5.dirname(destPath), { recursive: true });
9702
- fs4.copyFileSync(srcPath, destPath);
9703
- result.added.push(rel);
9704
- break;
9705
- case "unchanged":
9706
- result.unchanged.push(rel);
9707
- break;
9708
- case "stale":
9709
- fs4.copyFileSync(srcPath, destPath);
9710
- result.updated.push(rel);
9711
- break;
9712
- case "edited":
9713
- if (force) {
9714
- fs4.copyFileSync(srcPath, destPath);
9715
- result.updated.push(rel);
9716
- } else {
9717
- result.conflicts.push(rel);
9718
- }
9719
- break;
9720
- }
9721
- }
9722
- return result;
9723
- }
9724
- function buildManifest(skillName, recon, prior) {
9725
- const conflicts = new Set(recon.conflicts);
9726
- const files = {};
9727
- for (const [rel, bundledHash] of recon.bundledHashes) {
9728
- files[rel] = conflicts.has(rel) ? prior?.files[rel] ?? bundledHash : bundledHash;
9729
- }
9730
- return { skill: skillName, version: PACKAGE_VERSION, files };
9731
- }
9732
- function describeChanges(recon) {
9733
- const parts = [];
9734
- if (recon.added.length > 0) parts.push(`${recon.added.length} added`);
9735
- if (recon.updated.length > 0) parts.push(`${recon.updated.length} refreshed`);
9736
- return parts.length > 0 ? parts.join(", ") : "no changes";
9737
- }
9738
- function buildClaudeMessage(name, status, recon) {
9739
- const rel = `.claude/skills/${name}`;
9740
- let message = status === "installed" ? `Installed ${rel}` : status === "updated" ? `Updated ${rel} (${describeChanges(recon)})` : `Already installed: ${rel}`;
9741
- if (recon.conflicts.length > 0) {
9742
- message += ` \u2014 ${recon.conflicts.length} file(s) differ from the bundle (local edits kept; pass --force to overwrite)`;
9743
- }
9744
- return message;
9745
- }
9746
- function installClaudeSkill(skill, targetDir, force) {
9747
- const targetPath = path5.join(targetDir, ".claude", "skills", skill.name);
9748
- const existedBefore = fs4.existsSync(path5.join(targetPath, "SKILL.md"));
9749
- const priorManifest = readSkillManifest(targetPath);
9750
- fs4.mkdirSync(targetPath, { recursive: true });
9751
- const recon = reconcileSkillTree(skill.bundledPath, targetPath, priorManifest, force);
9752
- writeSkillManifest(targetPath, buildManifest(skill.name, recon, priorManifest));
9753
- const changed = recon.added.length + recon.updated.length;
9754
- const status = !existedBefore ? "installed" : changed > 0 ? "updated" : "already-installed";
9755
- return {
9756
- skill: skill.name,
9757
- client: CodingAgents.claude,
9758
- targetPath,
9759
- status,
9760
- message: buildClaudeMessage(skill.name, status, recon),
9761
- added: recon.added,
9762
- updated: recon.updated,
9763
- unchanged: recon.unchanged,
9764
- conflicts: recon.conflicts
9765
- };
9766
- }
9767
- function installCodexSymlink(skill, targetDir, force) {
9768
- const codexPath = path5.join(targetDir, ".codex", "skills", skill.name);
9769
- const claudePath = path5.join(targetDir, ".claude", "skills", skill.name);
9770
- const linkTarget = path5.relative(path5.dirname(codexPath), claudePath);
9771
- fs4.mkdirSync(path5.dirname(codexPath), { recursive: true });
9772
- let stat;
9773
- try {
9774
- stat = fs4.lstatSync(codexPath);
9775
- } catch {
9776
- stat = void 0;
9777
- }
9778
- if (stat?.isSymbolicLink()) {
9779
- const existing = fs4.readlinkSync(codexPath);
9780
- if (existing === linkTarget) {
9781
- return {
9782
- skill: skill.name,
9783
- client: CodingAgents.codex,
9784
- targetPath: codexPath,
9785
- status: "already-linked",
9786
- message: `Already linked: .codex/skills/${skill.name}`
9787
- };
9788
- }
9789
- if (!force) {
9790
- throw new CliError({
9791
- code: "VALIDATION_ERROR",
9792
- message: `.codex/skills/${skill.name} is a symlink pointing elsewhere (${existing}). Pass --force to relink.`,
9793
- details: { skill: skill.name, targetPath: codexPath, existingTarget: existing },
9794
- exitCode: 1
9795
- });
9796
- }
9797
- fs4.unlinkSync(codexPath);
9798
- fs4.symlinkSync(linkTarget, codexPath);
9799
- return {
9800
- skill: skill.name,
9801
- client: CodingAgents.codex,
9802
- targetPath: codexPath,
9803
- status: "relinked",
9804
- message: `Relinked .codex/skills/${skill.name} \u2192 ${linkTarget}`
9805
- };
9806
- }
9807
- if (stat) {
9808
- if (!force) {
9809
- throw new CliError({
9810
- code: "VALIDATION_ERROR",
9811
- message: `.codex/skills/${skill.name} exists but is not a symlink. Pass --force to replace.`,
9812
- details: { skill: skill.name, targetPath: codexPath },
9813
- exitCode: 1
9814
- });
9815
- }
9816
- fs4.rmSync(codexPath, { recursive: true, force: true });
9817
- }
9818
- fs4.symlinkSync(linkTarget, codexPath);
9819
- return {
9820
- skill: skill.name,
9821
- client: CodingAgents.codex,
9822
- targetPath: codexPath,
9823
- status: stat ? "relinked" : "linked",
9824
- message: stat ? `Replaced and linked .codex/skills/${skill.name} \u2192 ${linkTarget}` : `Linked .codex/skills/${skill.name} \u2192 ${linkTarget}`
9825
- };
9826
- }
9827
- function buildSummaryMessage(results) {
9828
- const counts = {};
9829
- for (const r of results) counts[r.status] = (counts[r.status] ?? 0) + 1;
9830
- const parts = Object.entries(counts).map(([status, n]) => `${n} ${status}`);
9831
- let message = `Skills install summary: ${parts.join(", ")}.`;
9832
- const totalConflicts = results.reduce((sum, r) => sum + (r.conflicts?.length ?? 0), 0);
9833
- if (totalConflicts > 0) {
9834
- message += ` ${totalConflicts} file(s) differ from the bundle and were kept \u2014 pass --force to overwrite local edits.`;
9835
- }
9836
- return message;
9837
- }
9838
- function getBundledSkillSnapshots(pkgDir) {
9839
- return getBundledSkills(pkgDir).map((skill) => {
9840
- const files = {};
9841
- for (const rel of walkRelative(skill.bundledPath)) {
9842
- files[rel] = sha256File(path5.join(skill.bundledPath, rel));
9843
- }
9844
- return { name: skill.name, version: PACKAGE_VERSION, files };
9845
- });
9846
- }
9847
- async function installSkills(opts = {}) {
9848
- const targetDir = opts.user ? os4.homedir() : path5.resolve(opts.dir ?? process.cwd());
9849
- const client = opts.client ?? SkillsClients.all;
9850
- const force = opts.force ?? false;
9851
- const allSkills = getBundledSkills();
9852
- const requestedNames = opts.skills && opts.skills.length > 0 ? opts.skills : allSkills.map((s) => s.name);
9853
- const knownNames = new Set(allSkills.map((s) => s.name));
9854
- const unknown = requestedNames.filter((n) => !knownNames.has(n));
9855
- if (unknown.length > 0) {
9856
- throw new CliError({
9857
- code: "VALIDATION_ERROR",
9858
- message: `Unknown skill(s): ${unknown.join(", ")}. Available: ${[...knownNames].join(", ")}`,
9859
- details: { unknownSkills: unknown, availableSkills: [...knownNames] },
9860
- exitCode: 1
9861
- });
9862
- }
9863
- const skillsToInstall = allSkills.filter((s) => requestedNames.includes(s.name));
9864
- fs4.mkdirSync(targetDir, { recursive: true });
9865
- const results = [];
9866
- for (const skill of skillsToInstall) {
9867
- results.push(installClaudeSkill(skill, targetDir, force));
9868
- if (client !== SkillsClients.claude) {
9869
- results.push(installCodexSymlink(skill, targetDir, force));
9870
- }
9871
- }
9872
- return {
9873
- targetDir,
9874
- results,
9875
- message: buildSummaryMessage(results)
9876
- };
9877
- }
9878
- async function listSkills(opts = {}) {
9879
- const skills = getBundledSkills();
9880
- if (isMachineFormat(opts.format)) {
9881
- console.log(JSON.stringify({
9882
- skills: skills.map((s) => ({
9883
- name: s.name,
9884
- description: s.description,
9885
- claudePath: `.claude/skills/${s.name}`,
9886
- codexPath: `.codex/skills/${s.name}`
9887
- }))
9888
- }, null, 2));
9889
- return;
9890
- }
9891
- console.log("Bundled canonry skills:\n");
9892
- for (const skill of skills) {
9893
- console.log(` ${skill.name}`);
9894
- if (skill.description) console.log(` ${skill.description}`);
9895
- console.log(` Claude: .claude/skills/${skill.name}/`);
9896
- console.log(` Codex: .codex/skills/${skill.name} (symlink \u2192 ../../.claude/skills/${skill.name})`);
9897
- console.log();
9898
- }
9899
- }
9900
- function emitInstallSummary(summary, format) {
9901
- if (isMachineFormat(format)) {
9902
- console.log(JSON.stringify(summary, null, 2));
9903
- return;
9904
- }
9905
- for (const r of summary.results) console.log(r.message);
9906
- console.log(`
9907
- Target: ${summary.targetDir}`);
9908
- console.log(summary.message);
9909
- }
9910
- function getMissingUserSkillsNudge(home, agentPlugin) {
9911
- if (!home) return null;
9912
- const skillsBase = path5.join(home, ".claude", "skills");
9913
- const installed = [];
9914
- const missing = [];
9915
- for (const name of BUNDLED_SKILL_NAMES) {
9916
- const skillFile = path5.join(skillsBase, name, "SKILL.md");
9917
- if (existsSafe(skillFile)) installed.push(name);
9918
- else missing.push(name);
9919
- }
9920
- if (agentPlugin && agentPlugin.configuredClients.length > 0) {
9921
- const unverifiedClients = agentPlugin.configuredClients.filter((client) => !agentPlugin.verifiedClients.includes(client));
9922
- const mismatchedClients = agentPlugin.verifiedClients.filter((client) => agentPlugin.verifiedClientVersions?.[client] !== PACKAGE_VERSION);
9923
- if (unverifiedClients.length === 0 && mismatchedClients.length === 0) return null;
9924
- const displayClients = (clients) => clients.map((client) => client === "claude-code" ? "Claude Code" : "Codex").join(" + ");
9925
- const problems = [];
9926
- if (unverifiedClients.length > 0) {
9927
- problems.push(`The Canonry plugin is enabled for ${displayClients(unverifiedClients)}, but its cached manifest and skill assets could not be verified.`);
9928
- }
9929
- if (mismatchedClients.length > 0) {
9930
- const versions = mismatchedClients.map((client) => `${client === "claude-code" ? "Claude Code" : "Codex"} v${agentPlugin.verifiedClientVersions?.[client] ?? "unknown"}`).join(", ");
9931
- problems.push(`${versions} ${mismatchedClients.length === 1 ? "does" : "do"} not match the running Canonry v${PACKAGE_VERSION}.`);
9932
- }
9933
- return {
9934
- message: `Tip: ${problems.join(" ")} Update or reinstall \`canonry@canonry\` with the affected client plugin manager.`,
9935
- missing,
9936
- installed
9937
- };
9938
- }
9939
- if (missing.length === 0) return null;
9940
- const fix = missing.length === BUNDLED_SKILL_NAMES.length ? "canonry skills install --user" : `canonry skills install ${missing.join(" ")} --user`;
9941
- return {
9942
- message: `Tip: ${missing.join(" + ")} skill${missing.length === 1 ? "" : "s"} not installed in ~/.claude/skills/. Run \`${fix}\` so Claude/Codex sessions on this host auto-load the canonry reference docs.`,
9943
- missing,
9944
- installed
9945
- };
9946
- }
9947
- function existsSafe(p) {
9948
- try {
9949
- return fs4.existsSync(p);
9950
- } catch {
9951
- return false;
9952
- }
9953
- }
9954
- function parseSkillsClient(value) {
9955
- if (!value) return SkillsClients.all;
9956
- const parsed = skillsClientSchema.safeParse(value);
9957
- if (parsed.success) return parsed.data;
9958
- const allowed = skillsClientSchema.options;
9959
- throw new CliError({
9960
- code: "VALIDATION_ERROR",
9961
- message: `Invalid --client value "${value}". Must be one of: ${allowed.join(", ")}`,
9962
- details: { flag: "client", value, allowed },
9963
- exitCode: 1
9964
- });
9965
- }
9966
-
9967
9614
  // src/provider-registry.ts
9968
9615
  var ProviderRegistry = class {
9969
9616
  providers = /* @__PURE__ */ new Map();
@@ -10016,7 +9663,7 @@ var ProviderRegistry = class {
10016
9663
  };
10017
9664
 
10018
9665
  // src/scheduler.ts
10019
- import crypto19 from "crypto";
9666
+ import crypto18 from "crypto";
10020
9667
  import cron from "node-cron";
10021
9668
  import { and as and14, eq as eq17, inArray as inArray6, notExists, sql as sql8 } from "drizzle-orm";
10022
9669
  var log13 = createLogger("Scheduler");
@@ -10059,7 +9706,7 @@ var Scheduler = class {
10059
9706
  const now = (/* @__PURE__ */ new Date()).toISOString();
10060
9707
  for (const project of projectsWithoutHealth) {
10061
9708
  this.db.insert(schedules).values({
10062
- id: crypto19.randomUUID(),
9709
+ id: crypto18.randomUUID(),
10063
9710
  projectId: project.id,
10064
9711
  kind: SchedulableRunKinds.doctor,
10065
9712
  cronExpr: DEFAULT_HEALTH_CRON,
@@ -10218,7 +9865,7 @@ var Scheduler = class {
10218
9865
  log13.warn("gbp-sync.no-callback", { scheduleId, projectId, msg: "host did not register onGbpSyncRequested" });
10219
9866
  return;
10220
9867
  }
10221
- const runId2 = crypto19.randomUUID();
9868
+ const runId2 = crypto18.randomUUID();
10222
9869
  this.db.insert(runs).values({
10223
9870
  id: runId2,
10224
9871
  projectId,
@@ -10251,7 +9898,7 @@ var Scheduler = class {
10251
9898
  this.db.update(schedules).set({ nextRunAt, updatedAt: now }).where(eq17(schedules.id, currentSchedule.id)).run();
10252
9899
  return;
10253
9900
  }
10254
- const runId2 = crypto19.randomUUID();
9901
+ const runId2 = crypto18.randomUUID();
10255
9902
  this.db.insert(runs).values({
10256
9903
  id: runId2,
10257
9904
  projectId,
@@ -10326,7 +9973,7 @@ var Scheduler = class {
10326
9973
  this.db.update(schedules).set({ nextRunAt, updatedAt: now }).where(eq17(schedules.id, currentSchedule.id)).run();
10327
9974
  return;
10328
9975
  }
10329
- const runId2 = crypto19.randomUUID();
9976
+ const runId2 = crypto18.randomUUID();
10330
9977
  const effectiveRequest = normalizeSiteAuditRunRequest({});
10331
9978
  this.db.transaction((tx) => {
10332
9979
  tx.insert(runs).values({
@@ -10424,7 +10071,7 @@ async function refreshAllIntegrations(client, projectName) {
10424
10071
 
10425
10072
  // src/notifier.ts
10426
10073
  import { eq as eq18, desc as desc7, and as and15, inArray as inArray7, or as or2 } from "drizzle-orm";
10427
- import crypto20 from "crypto";
10074
+ import crypto19 from "crypto";
10428
10075
  var log15 = createLogger("Notifier");
10429
10076
  var Notifier = class {
10430
10077
  db;
@@ -10750,7 +10397,7 @@ var Notifier = class {
10750
10397
  }
10751
10398
  logDelivery(projectId, notificationId, event, status, error) {
10752
10399
  this.db.insert(auditLog).values({
10753
- id: crypto20.randomUUID(),
10400
+ id: crypto19.randomUUID(),
10754
10401
  projectId,
10755
10402
  actor: "scheduler",
10756
10403
  action: `notification.${status}`,
@@ -10912,12 +10559,12 @@ function analysisResultFromInsights(insights2) {
10912
10559
  }
10913
10560
 
10914
10561
  // src/agent/session-registry.ts
10915
- import crypto24 from "crypto";
10562
+ import crypto23 from "crypto";
10916
10563
  import { eq as eq21 } from "drizzle-orm";
10917
10564
 
10918
10565
  // src/agent/session.ts
10919
- import fs7 from "fs";
10920
- import path8 from "path";
10566
+ import fs6 from "fs";
10567
+ import path7 from "path";
10921
10568
  import { Agent } from "@mariozechner/pi-agent-core";
10922
10569
  import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
10923
10570
 
@@ -11160,26 +10807,26 @@ function buildAgentProvidersResponse(config) {
11160
10807
  }
11161
10808
 
11162
10809
  // src/agent/skill-paths.ts
11163
- import fs5 from "fs";
11164
- import path6 from "path";
11165
- import { fileURLToPath as fileURLToPath2 } from "url";
10810
+ import fs4 from "fs";
10811
+ import path5 from "path";
10812
+ import { fileURLToPath } from "url";
11166
10813
  function resolveAeroSkillDir(pkgDir) {
11167
- const here = pkgDir ?? path6.dirname(fileURLToPath2(import.meta.url));
10814
+ const here = pkgDir ?? path5.dirname(fileURLToPath(import.meta.url));
11168
10815
  const candidates = [
11169
- path6.join(here, "../assets/agent-workspace/skills/aero"),
11170
- path6.join(here, "../../assets/agent-workspace/skills/aero"),
11171
- path6.join(here, "../../../../skills/aero")
10816
+ path5.join(here, "../assets/agent-workspace/skills/aero"),
10817
+ path5.join(here, "../../assets/agent-workspace/skills/aero"),
10818
+ path5.join(here, "../../../../skills/aero")
11172
10819
  ];
11173
10820
  for (const candidate of candidates) {
11174
- if (fs5.existsSync(path6.join(candidate, "SKILL.md"))) return candidate;
10821
+ if (fs4.existsSync(path5.join(candidate, "SKILL.md"))) return candidate;
11175
10822
  }
11176
10823
  throw new Error(`Aero skill not found. Searched:
11177
10824
  ${candidates.join("\n ")}`);
11178
10825
  }
11179
10826
 
11180
10827
  // src/agent/skill-tools.ts
11181
- import fs6 from "fs";
11182
- import path7 from "path";
10828
+ import fs5 from "fs";
10829
+ import path6 from "path";
11183
10830
  import { Type } from "@sinclair/typebox";
11184
10831
  var MAX_DOC_CHARS = 2e4;
11185
10832
  function textResult(details) {
@@ -11188,7 +10835,7 @@ function textResult(details) {
11188
10835
  details
11189
10836
  };
11190
10837
  }
11191
- function parseDescription2(body) {
10838
+ function parseDescription(body) {
11192
10839
  if (!body.startsWith("---")) return "(no description)";
11193
10840
  const end = body.indexOf("\n---", 3);
11194
10841
  if (end === -1) return "(no description)";
@@ -11200,16 +10847,16 @@ function parseDescription2(body) {
11200
10847
  return "(no description)";
11201
10848
  }
11202
10849
  function scanSkillDocs(skillDir) {
11203
- const refsDir = path7.join(skillDir ?? resolveAeroSkillDir(), "references");
11204
- if (!fs6.existsSync(refsDir)) return [];
10850
+ const refsDir = path6.join(skillDir ?? resolveAeroSkillDir(), "references");
10851
+ if (!fs5.existsSync(refsDir)) return [];
11205
10852
  const entries = [];
11206
- for (const file of fs6.readdirSync(refsDir)) {
10853
+ for (const file of fs5.readdirSync(refsDir)) {
11207
10854
  if (!file.endsWith(".md")) continue;
11208
- const filePath = path7.join(refsDir, file);
11209
- const body = fs6.readFileSync(filePath, "utf-8");
10855
+ const filePath = path6.join(refsDir, file);
10856
+ const body = fs5.readFileSync(filePath, "utf-8");
11210
10857
  entries.push({
11211
10858
  slug: file.replace(/\.md$/, ""),
11212
- description: parseDescription2(body),
10859
+ description: parseDescription(body),
11213
10860
  bytes: Buffer.byteLength(body, "utf-8")
11214
10861
  });
11215
10862
  }
@@ -11249,8 +10896,8 @@ function buildReadSkillDocTool() {
11249
10896
  availableSlugs: docs.map((d) => d.slug)
11250
10897
  });
11251
10898
  }
11252
- const filePath = path7.join(skillDir, "references", `${match.slug}.md`);
11253
- const content = fs6.readFileSync(filePath, "utf-8");
10899
+ const filePath = path6.join(skillDir, "references", `${match.slug}.md`);
10900
+ const content = fs5.readFileSync(filePath, "utf-8");
11254
10901
  if (content.length > MAX_DOC_CHARS) {
11255
10902
  return textResult({
11256
10903
  slug: match.slug,
@@ -11656,7 +11303,7 @@ function buildAeroStateTools(ctx, opts = {}) {
11656
11303
  }
11657
11304
 
11658
11305
  // src/agent/llm-usage.ts
11659
- import crypto21 from "crypto";
11306
+ import crypto20 from "crypto";
11660
11307
  var AeroLlmUsageFeatures = {
11661
11308
  turn: "aero.turn"
11662
11309
  };
@@ -11675,7 +11322,7 @@ function recordLlmUsageEvent(args) {
11675
11322
  const usage = args.message.usage;
11676
11323
  const now = (/* @__PURE__ */ new Date()).toISOString();
11677
11324
  args.db.insert(llmUsageEvents).values({
11678
- id: crypto21.randomUUID(),
11325
+ id: crypto20.randomUUID(),
11679
11326
  projectId: args.projectId,
11680
11327
  runId: args.runId,
11681
11328
  agentSessionId: args.agentSessionId,
@@ -11751,7 +11398,7 @@ function splitAeroAnthropicSystemCachePayload(payload, model) {
11751
11398
  }
11752
11399
 
11753
11400
  // src/agent/tool-usage.ts
11754
- import crypto22 from "crypto";
11401
+ import crypto21 from "crypto";
11755
11402
  var AeroToolEventStatuses = {
11756
11403
  success: "success",
11757
11404
  error: "error"
@@ -11814,7 +11461,7 @@ function createAeroToolUsageHooks(args) {
11814
11461
  function recordAgentToolEvent(args) {
11815
11462
  try {
11816
11463
  args.db.insert(agentToolEvents).values({
11817
- id: crypto22.randomUUID(),
11464
+ id: crypto21.randomUUID(),
11818
11465
  projectId: args.projectId,
11819
11466
  agentSessionId: args.agentSessionId,
11820
11467
  toolCallId: args.toolCallId,
@@ -11845,9 +11492,9 @@ function ensureBuiltinsRegistered() {
11845
11492
  }
11846
11493
  function loadAeroSystemPrompt(pkgDir) {
11847
11494
  const skillDir = resolveAeroSkillDir(pkgDir);
11848
- const skillBody = fs7.readFileSync(path8.join(skillDir, "SKILL.md"), "utf-8");
11849
- const soulPath = path8.join(skillDir, "soul.md");
11850
- const base = fs7.existsSync(soulPath) ? `${fs7.readFileSync(soulPath, "utf-8").trimEnd()}
11495
+ const skillBody = fs6.readFileSync(path7.join(skillDir, "SKILL.md"), "utf-8");
11496
+ const soulPath = path7.join(skillDir, "soul.md");
11497
+ const base = fs6.existsSync(soulPath) ? `${fs6.readFileSync(soulPath, "utf-8").trimEnd()}
11851
11498
 
11852
11499
  ---
11853
11500
 
@@ -11860,7 +11507,7 @@ function appendSystemPromptExtras(base, env = process.env) {
11860
11507
  const filePath = env.AERO_SYSTEM_PROMPT_FILE?.trim();
11861
11508
  if (filePath) {
11862
11509
  try {
11863
- fileBody = fs7.readFileSync(filePath, "utf-8").trim();
11510
+ fileBody = fs6.readFileSync(filePath, "utf-8").trim();
11864
11511
  } catch {
11865
11512
  fileBody = "";
11866
11513
  }
@@ -12041,7 +11688,7 @@ async function loadExternalMcpTools(servers, opts = {}) {
12041
11688
  }
12042
11689
 
12043
11690
  // src/agent/memory-store.ts
12044
- import crypto23 from "crypto";
11691
+ import crypto22 from "crypto";
12045
11692
  import { and as and16, desc as desc8, eq as eq20, like, sql as sql9 } from "drizzle-orm";
12046
11693
  var COMPACTION_KEY_PREFIX = "compaction:";
12047
11694
  var COMPACTION_NOTES_PER_SESSION = 3;
@@ -12070,7 +11717,7 @@ function upsertMemoryEntry(db, args) {
12070
11717
  throw new Error(`memory key prefix "${COMPACTION_KEY_PREFIX}" is reserved for compaction notes`);
12071
11718
  }
12072
11719
  const now = (/* @__PURE__ */ new Date()).toISOString();
12073
- const id = crypto23.randomUUID();
11720
+ const id = crypto22.randomUUID();
12074
11721
  db.insert(agentMemory).values({
12075
11722
  id,
12076
11723
  projectId: args.projectId,
@@ -12107,7 +11754,7 @@ function writeCompactionNote(db, args) {
12107
11754
  }
12108
11755
  const now = (/* @__PURE__ */ new Date()).toISOString();
12109
11756
  const key = `${COMPACTION_KEY_PREFIX}${args.sessionId}:${now}`;
12110
- const id = crypto23.randomUUID();
11757
+ const id = crypto22.randomUUID();
12111
11758
  let inserted;
12112
11759
  db.transaction((tx) => {
12113
11760
  tx.insert(agentMemory).values({
@@ -12386,7 +12033,7 @@ var SessionRegistry = class {
12386
12033
  }
12387
12034
  const { provider, modelId } = resolveSessionProviderAndModel(this.opts.config, preferences);
12388
12035
  const systemPrompt = loadAeroSystemPrompt();
12389
- const sessionId = crypto24.randomUUID();
12036
+ const sessionId = crypto23.randomUUID();
12390
12037
  const agent = createAeroSession({
12391
12038
  projectName,
12392
12039
  client: this.opts.client,
@@ -12765,7 +12412,7 @@ ${lines.join("\n")}
12765
12412
  insertRow(params) {
12766
12413
  const now = (/* @__PURE__ */ new Date()).toISOString();
12767
12414
  this.opts.db.insert(agentSessions).values({
12768
- id: params.id ?? crypto24.randomUUID(),
12415
+ id: params.id ?? crypto23.randomUUID(),
12769
12416
  projectId: params.projectId,
12770
12417
  systemPrompt: params.systemPrompt,
12771
12418
  modelProvider: params.provider ?? params.modelProvider ?? AgentProviderIds.claude,
@@ -13153,13 +12800,13 @@ var USER_AGENT2 = "Canonry/1.0 (site-analysis)";
13153
12800
  function fetchWithPinnedAddress(target) {
13154
12801
  return new Promise((resolve) => {
13155
12802
  const port = target.url.port ? Number(target.url.port) : 443;
13156
- const path10 = target.url.pathname + target.url.search;
12803
+ const path9 = target.url.pathname + target.url.search;
13157
12804
  const req = https2.request(
13158
12805
  {
13159
12806
  hostname: target.address,
13160
12807
  family: target.family,
13161
12808
  port,
13162
- path: path10,
12809
+ path: path9,
13163
12810
  method: "GET",
13164
12811
  timeout: FETCH_TIMEOUT_MS2,
13165
12812
  servername: target.url.hostname,
@@ -13948,14 +13595,14 @@ function summarizeProviderConfig(config) {
13948
13595
  };
13949
13596
  }
13950
13597
  function hashApiKey(key) {
13951
- return crypto25.createHash("sha256").update(key).digest("hex");
13598
+ return crypto24.createHash("sha256").update(key).digest("hex");
13952
13599
  }
13953
13600
  var DASHBOARD_SCRYPT_KEYLEN = 64;
13954
13601
  var DASHBOARD_SCRYPT_COST = 1 << 15;
13955
13602
  var DASHBOARD_SCRYPT_MAXMEM = 64 * 1024 * 1024;
13956
13603
  function hashDashboardPassword(password) {
13957
- const salt = crypto25.randomBytes(16);
13958
- const derived = crypto25.scryptSync(password, salt, DASHBOARD_SCRYPT_KEYLEN, {
13604
+ const salt = crypto24.randomBytes(16);
13605
+ const derived = crypto24.scryptSync(password, salt, DASHBOARD_SCRYPT_KEYLEN, {
13959
13606
  N: DASHBOARD_SCRYPT_COST,
13960
13607
  maxmem: DASHBOARD_SCRYPT_MAXMEM
13961
13608
  });
@@ -13976,14 +13623,14 @@ function verifyDashboardPassword(password, storedHash) {
13976
13623
  } catch {
13977
13624
  return { ok: false, needsRehash: false };
13978
13625
  }
13979
- const derived = crypto25.scryptSync(password, salt, expected.length, {
13626
+ const derived = crypto24.scryptSync(password, salt, expected.length, {
13980
13627
  N: DASHBOARD_SCRYPT_COST,
13981
13628
  maxmem: DASHBOARD_SCRYPT_MAXMEM
13982
13629
  });
13983
13630
  if (derived.length !== expected.length)
13984
13631
  return { ok: false, needsRehash: false };
13985
13632
  return {
13986
- ok: crypto25.timingSafeEqual(derived, expected),
13633
+ ok: crypto24.timingSafeEqual(derived, expected),
13987
13634
  needsRehash: false
13988
13635
  };
13989
13636
  }
@@ -13992,7 +13639,7 @@ function verifyDashboardPassword(password, storedHash) {
13992
13639
  const expected = Buffer.from(storedHash, "hex");
13993
13640
  if (candidate.length !== expected.length)
13994
13641
  return { ok: false, needsRehash: false };
13995
- const ok = crypto25.timingSafeEqual(candidate, expected);
13642
+ const ok = crypto24.timingSafeEqual(candidate, expected);
13996
13643
  return { ok, needsRehash: ok };
13997
13644
  }
13998
13645
  return { ok: false, needsRehash: false };
@@ -14223,8 +13870,8 @@ async function createServer(opts) {
14223
13870
  );
14224
13871
  jobRunner.onRunCompleted = (runId, projectId) => runCoordinator.onRunCompleted(runId, projectId);
14225
13872
  const snapshotService = new SnapshotService(registry);
14226
- const orphanedOpenClawDir = path9.join(os5.homedir(), ".openclaw-aero");
14227
- if (fs8.existsSync(orphanedOpenClawDir)) {
13873
+ const orphanedOpenClawDir = path8.join(os4.homedir(), ".openclaw-aero");
13874
+ if (fs7.existsSync(orphanedOpenClawDir)) {
14228
13875
  app.log.warn(
14229
13876
  { path: orphanedOpenClawDir },
14230
13877
  "OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
@@ -14761,7 +14408,7 @@ async function createServer(opts) {
14761
14408
  return removed;
14762
14409
  }
14763
14410
  };
14764
- const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto25.randomBytes(32).toString("hex");
14411
+ const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto24.randomBytes(32).toString("hex");
14765
14412
  const googleConnectionStore = {
14766
14413
  listConnections: (domain) => listGoogleConnections(opts.config, domain),
14767
14414
  getConnection: (domain, connectionType) => getGoogleConnection(opts.config, domain, connectionType),
@@ -14841,7 +14488,7 @@ async function createServer(opts) {
14841
14488
  if (!existing) {
14842
14489
  const prefix = opts.config.apiKey.slice(0, 12);
14843
14490
  opts.db.insert(apiKeys).values({
14844
- id: `key_${crypto25.randomBytes(8).toString("hex")}`,
14491
+ id: `key_${crypto24.randomBytes(8).toString("hex")}`,
14845
14492
  name: "default",
14846
14493
  keyHash,
14847
14494
  keyPrefix: prefix,
@@ -14865,7 +14512,7 @@ async function createServer(opts) {
14865
14512
  };
14866
14513
  const createSession = (apiKeyId) => {
14867
14514
  pruneExpiredSessions();
14868
- const sessionId = crypto25.randomBytes(32).toString("hex");
14515
+ const sessionId = crypto24.randomBytes(32).toString("hex");
14869
14516
  sessions.set(sessionId, {
14870
14517
  apiKeyId,
14871
14518
  expiresAt: Date.now() + SESSION_TTL_MS
@@ -15113,7 +14760,7 @@ async function createServer(opts) {
15113
14760
  const configPath = getConfigPath();
15114
14761
  return {
15115
14762
  databasePath: opts.config.database,
15116
- configPath: fs8.existsSync(configPath) ? configPath : null
14763
+ configPath: fs7.existsSync(configPath) ? configPath : null
15117
14764
  };
15118
14765
  })(),
15119
14766
  // Snapshot the bundled skill trees (version + file hashes) so the
@@ -15225,7 +14872,7 @@ async function createServer(opts) {
15225
14872
  deps: {
15226
14873
  enqueueAutoExtract: ({ projectId, release: r }) => {
15227
14874
  const now = (/* @__PURE__ */ new Date()).toISOString();
15228
- const runId = crypto25.randomUUID();
14875
+ const runId = crypto24.randomUUID();
15229
14876
  opts.db.insert(runs).values({
15230
14877
  id: runId,
15231
14878
  projectId,
@@ -15460,7 +15107,7 @@ async function createServer(opts) {
15460
15107
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
15461
15108
  opts.db.insert(auditLog).values(
15462
15109
  targetProjectIds.map((projectId) => ({
15463
- id: crypto25.randomUUID(),
15110
+ id: crypto24.randomUUID(),
15464
15111
  projectId,
15465
15112
  actor: "api",
15466
15113
  action: existing ? "provider.updated" : "provider.created",
@@ -15619,10 +15266,10 @@ async function createServer(opts) {
15619
15266
  return snapshotService.createReport(input);
15620
15267
  }
15621
15268
  });
15622
- const dirname = path9.dirname(fileURLToPath3(import.meta.url));
15623
- const assetsDir = opts.assetsDir ?? path9.join(dirname, "..", "assets");
15624
- if (fs8.existsSync(assetsDir)) {
15625
- const indexPath = path9.join(assetsDir, "index.html");
15269
+ const dirname = path8.dirname(fileURLToPath2(import.meta.url));
15270
+ const assetsDir = opts.assetsDir ?? path8.join(dirname, "..", "assets");
15271
+ if (fs7.existsSync(assetsDir)) {
15272
+ const indexPath = path8.join(assetsDir, "index.html");
15626
15273
  const injectConfig = (html, projectTabsOverride, themeOverride, renderTokenOverride) => {
15627
15274
  const clientConfig = {};
15628
15275
  if (basePath) clientConfig.basePath = basePath;
@@ -15677,8 +15324,8 @@ async function createServer(opts) {
15677
15324
  // Without this, the browser hits the server for every JS chunk on
15678
15325
  // every page load, defeating most of the dashboard's first-paint
15679
15326
  // budget.
15680
- setHeaders: (res, path10) => {
15681
- if (path10.endsWith(".html")) {
15327
+ setHeaders: (res, path9) => {
15328
+ if (path9.endsWith(".html")) {
15682
15329
  res.setHeader("Cache-Control", "no-cache, must-revalidate");
15683
15330
  } else {
15684
15331
  res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
@@ -15686,8 +15333,8 @@ async function createServer(opts) {
15686
15333
  }
15687
15334
  });
15688
15335
  const serveIndex = (_request, reply) => {
15689
- if (fs8.existsSync(indexPath)) {
15690
- const html = fs8.readFileSync(indexPath, "utf-8");
15336
+ if (fs7.existsSync(indexPath)) {
15337
+ const html = fs7.readFileSync(indexPath, "utf-8");
15691
15338
  return sendSpaDocument(reply, html);
15692
15339
  }
15693
15340
  return reply.status(404).send({ error: "Dashboard not built" });
@@ -15708,8 +15355,8 @@ async function createServer(opts) {
15708
15355
  if (basePath && !url.startsWith(basePath)) {
15709
15356
  return reply.status(404).send({ error: "Not found", path: request.url });
15710
15357
  }
15711
- if (fs8.existsSync(indexPath)) {
15712
- const html = fs8.readFileSync(indexPath, "utf-8");
15358
+ if (fs7.existsSync(indexPath)) {
15359
+ const html = fs7.readFileSync(indexPath, "utf-8");
15713
15360
  return sendSpaDocument(reply, html);
15714
15361
  }
15715
15362
  return reply.status(404).send({ error: "Not found" });
@@ -15816,11 +15463,6 @@ export {
15816
15463
  backfillTrafficClassificationCommand,
15817
15464
  getCloudflareTrafficConnectionBySourceId,
15818
15465
  setGoogleAuthConfig,
15819
- installSkills,
15820
- listSkills,
15821
- emitInstallSummary,
15822
- getMissingUserSkillsNudge,
15823
- parseSkillsClient,
15824
15466
  formatAuditFactorScore,
15825
15467
  checkLatestVersionForCli,
15826
15468
  listAgentProviders,