@canonry/canonry 4.167.0 → 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.
- package/README.md +31 -19
- package/assets/agent-workspace/skills/aero/SKILL.md +1 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
- package/dist/chunk-76JMZAFZ.js +123 -0
- package/dist/{chunk-P5LR3NDQ.js → chunk-C4UWZLQX.js} +399 -8
- package/dist/{chunk-7M3QVRJD.js → chunk-CDACTPTY.js} +79 -1
- package/dist/{chunk-SXENNCJF.js → chunk-R2SZWJDV.js} +96 -452
- package/dist/cli.js +16 -8
- package/dist/index.d.ts +19 -0
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-ULDOVV5Y.js → intelligence-service-KBSDKHED.js} +1 -1
- package/dist/mcp.js +23 -1
- package/package.json +10 -10
|
@@ -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-
|
|
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-
|
|
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
|
|
589
|
-
import
|
|
590
|
-
import
|
|
591
|
-
import { fileURLToPath as
|
|
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
|
|
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(
|
|
5177
|
+
function buildUrl(path9, queryPairs) {
|
|
5185
5178
|
const qs = queryPairs.join("&");
|
|
5186
|
-
return qs ? `${OPENAI_ADS_API_BASE}/${
|
|
5179
|
+
return qs ? `${OPENAI_ADS_API_BASE}/${path9}?${qs}` : `${OPENAI_ADS_API_BASE}/${path9}`;
|
|
5187
5180
|
}
|
|
5188
|
-
async function adsFetch(apiKey,
|
|
5189
|
-
const url = buildUrl(
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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,
|
|
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:
|
|
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(
|
|
7398
|
-
return
|
|
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
|
|
8030
|
-
if (
|
|
8031
|
-
const trimmed =
|
|
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
|
}
|
|
@@ -8098,12 +8091,14 @@ function deadLinkCheckedCount(edges, pages) {
|
|
|
8098
8091
|
}
|
|
8099
8092
|
return new Set([...edges].filter((edge) => edge.type === "anchor" && edge.classification === "internal" && attemptedUrls.has(edge.to)).map((edge) => edge.to)).size;
|
|
8100
8093
|
}
|
|
8094
|
+
var RATE_LIMITED_STATUS = 429;
|
|
8101
8095
|
function partitionDeadLinks(deadLinks) {
|
|
8102
8096
|
const reported = deadLinks.findings;
|
|
8103
8097
|
const engineUnverified = deadLinks.unverified ?? [];
|
|
8104
|
-
const
|
|
8098
|
+
const answeredWithError = (finding) => typeof finding.statusCode === "number" && finding.statusCode >= 400;
|
|
8099
|
+
const dead = reported.filter((finding) => answeredWithError(finding) && finding.statusCode !== RATE_LIMITED_STATUS);
|
|
8105
8100
|
const unverified = [
|
|
8106
|
-
...reported.filter((finding) =>
|
|
8101
|
+
...reported.filter((finding) => !answeredWithError(finding) || finding.statusCode === RATE_LIMITED_STATUS),
|
|
8107
8102
|
...engineUnverified
|
|
8108
8103
|
];
|
|
8109
8104
|
return { dead, unverified };
|
|
@@ -9092,7 +9087,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
9092
9087
|
return result;
|
|
9093
9088
|
}
|
|
9094
9089
|
async function backfillInsightsCommand(project, opts) {
|
|
9095
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
9090
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-KBSDKHED.js");
|
|
9096
9091
|
const config = loadConfig();
|
|
9097
9092
|
const db = createClient(config.database);
|
|
9098
9093
|
migrate(db);
|
|
@@ -9616,352 +9611,6 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
9616
9611
|
}
|
|
9617
9612
|
}
|
|
9618
9613
|
|
|
9619
|
-
// src/commands/skills.ts
|
|
9620
|
-
import crypto18 from "crypto";
|
|
9621
|
-
import fs4 from "fs";
|
|
9622
|
-
import os4 from "os";
|
|
9623
|
-
import path5 from "path";
|
|
9624
|
-
import { fileURLToPath } from "url";
|
|
9625
|
-
var BUNDLED_SKILL_NAMES = ["canonry", "aero"];
|
|
9626
|
-
function resolveBundledSkillsRoot(pkgDir) {
|
|
9627
|
-
const here = pkgDir ?? path5.dirname(fileURLToPath(import.meta.url));
|
|
9628
|
-
const candidates = [
|
|
9629
|
-
path5.join(here, "../assets/agent-workspace/skills"),
|
|
9630
|
-
path5.join(here, "../../assets/agent-workspace/skills"),
|
|
9631
|
-
path5.join(here, "../../../../skills")
|
|
9632
|
-
];
|
|
9633
|
-
for (const candidate of candidates) {
|
|
9634
|
-
if (BUNDLED_SKILL_NAMES.every((name) => fs4.existsSync(path5.join(candidate, name, "SKILL.md")))) {
|
|
9635
|
-
return candidate;
|
|
9636
|
-
}
|
|
9637
|
-
}
|
|
9638
|
-
throw new CliError({
|
|
9639
|
-
code: "INTERNAL_ERROR",
|
|
9640
|
-
message: `Bundled skills not found. Searched:
|
|
9641
|
-
${candidates.join("\n ")}`,
|
|
9642
|
-
exitCode: 2
|
|
9643
|
-
});
|
|
9644
|
-
}
|
|
9645
|
-
function parseDescription(content) {
|
|
9646
|
-
const fmMatch = /^---\n([\s\S]*?)\n---/.exec(content);
|
|
9647
|
-
if (!fmMatch) return "";
|
|
9648
|
-
const descMatch = /^description:\s*(\S.*)$/m.exec(fmMatch[1]);
|
|
9649
|
-
if (!descMatch) return "";
|
|
9650
|
-
return descMatch[1].replace(/^["']|["']$/g, "").trim();
|
|
9651
|
-
}
|
|
9652
|
-
function getBundledSkills(pkgDir) {
|
|
9653
|
-
const root = resolveBundledSkillsRoot(pkgDir);
|
|
9654
|
-
return BUNDLED_SKILL_NAMES.map((name) => {
|
|
9655
|
-
const skillDir = path5.join(root, name);
|
|
9656
|
-
const skillFile = path5.join(skillDir, "SKILL.md");
|
|
9657
|
-
const content = fs4.readFileSync(skillFile, "utf-8");
|
|
9658
|
-
return { name, description: parseDescription(content), bundledPath: skillDir };
|
|
9659
|
-
});
|
|
9660
|
-
}
|
|
9661
|
-
function walkRelative(dir, prefix = "") {
|
|
9662
|
-
const out = [];
|
|
9663
|
-
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
9664
|
-
const rel = prefix ? path5.join(prefix, entry.name) : entry.name;
|
|
9665
|
-
const full = path5.join(dir, entry.name);
|
|
9666
|
-
if (entry.isDirectory()) {
|
|
9667
|
-
out.push(...walkRelative(full, rel));
|
|
9668
|
-
} else if (entry.isFile()) {
|
|
9669
|
-
out.push(rel);
|
|
9670
|
-
}
|
|
9671
|
-
}
|
|
9672
|
-
return out.sort();
|
|
9673
|
-
}
|
|
9674
|
-
function sha256File(filePath) {
|
|
9675
|
-
return crypto18.createHash("sha256").update(fs4.readFileSync(filePath)).digest("hex");
|
|
9676
|
-
}
|
|
9677
|
-
function readSkillManifest(skillDir) {
|
|
9678
|
-
try {
|
|
9679
|
-
return coerceSkillManifest(JSON.parse(fs4.readFileSync(path5.join(skillDir, SKILL_MANIFEST_FILENAME), "utf-8")));
|
|
9680
|
-
} catch {
|
|
9681
|
-
return null;
|
|
9682
|
-
}
|
|
9683
|
-
}
|
|
9684
|
-
function writeSkillManifest(skillDir, manifest) {
|
|
9685
|
-
fs4.writeFileSync(path5.join(skillDir, SKILL_MANIFEST_FILENAME), `${JSON.stringify(manifest, null, 2)}
|
|
9686
|
-
`, "utf-8");
|
|
9687
|
-
}
|
|
9688
|
-
function reconcileSkillTree(srcDir, destDir, manifest, force) {
|
|
9689
|
-
const result = { added: [], updated: [], unchanged: [], conflicts: [], bundledHashes: /* @__PURE__ */ new Map() };
|
|
9690
|
-
for (const rel of walkRelative(srcDir)) {
|
|
9691
|
-
const srcPath = path5.join(srcDir, rel);
|
|
9692
|
-
const destPath = path5.join(destDir, rel);
|
|
9693
|
-
const bundledHash = sha256File(srcPath);
|
|
9694
|
-
result.bundledHashes.set(rel, bundledHash);
|
|
9695
|
-
const installedHash = fs4.existsSync(destPath) ? sha256File(destPath) : void 0;
|
|
9696
|
-
const state = classifySkillFile({ bundledHash, installedHash, manifestHash: manifest?.files[rel] });
|
|
9697
|
-
switch (state) {
|
|
9698
|
-
case "missing":
|
|
9699
|
-
fs4.mkdirSync(path5.dirname(destPath), { recursive: true });
|
|
9700
|
-
fs4.copyFileSync(srcPath, destPath);
|
|
9701
|
-
result.added.push(rel);
|
|
9702
|
-
break;
|
|
9703
|
-
case "unchanged":
|
|
9704
|
-
result.unchanged.push(rel);
|
|
9705
|
-
break;
|
|
9706
|
-
case "stale":
|
|
9707
|
-
fs4.copyFileSync(srcPath, destPath);
|
|
9708
|
-
result.updated.push(rel);
|
|
9709
|
-
break;
|
|
9710
|
-
case "edited":
|
|
9711
|
-
if (force) {
|
|
9712
|
-
fs4.copyFileSync(srcPath, destPath);
|
|
9713
|
-
result.updated.push(rel);
|
|
9714
|
-
} else {
|
|
9715
|
-
result.conflicts.push(rel);
|
|
9716
|
-
}
|
|
9717
|
-
break;
|
|
9718
|
-
}
|
|
9719
|
-
}
|
|
9720
|
-
return result;
|
|
9721
|
-
}
|
|
9722
|
-
function buildManifest(skillName, recon, prior) {
|
|
9723
|
-
const conflicts = new Set(recon.conflicts);
|
|
9724
|
-
const files = {};
|
|
9725
|
-
for (const [rel, bundledHash] of recon.bundledHashes) {
|
|
9726
|
-
files[rel] = conflicts.has(rel) ? prior?.files[rel] ?? bundledHash : bundledHash;
|
|
9727
|
-
}
|
|
9728
|
-
return { skill: skillName, version: PACKAGE_VERSION, files };
|
|
9729
|
-
}
|
|
9730
|
-
function describeChanges(recon) {
|
|
9731
|
-
const parts = [];
|
|
9732
|
-
if (recon.added.length > 0) parts.push(`${recon.added.length} added`);
|
|
9733
|
-
if (recon.updated.length > 0) parts.push(`${recon.updated.length} refreshed`);
|
|
9734
|
-
return parts.length > 0 ? parts.join(", ") : "no changes";
|
|
9735
|
-
}
|
|
9736
|
-
function buildClaudeMessage(name, status, recon) {
|
|
9737
|
-
const rel = `.claude/skills/${name}`;
|
|
9738
|
-
let message = status === "installed" ? `Installed ${rel}` : status === "updated" ? `Updated ${rel} (${describeChanges(recon)})` : `Already installed: ${rel}`;
|
|
9739
|
-
if (recon.conflicts.length > 0) {
|
|
9740
|
-
message += ` \u2014 ${recon.conflicts.length} file(s) differ from the bundle (local edits kept; pass --force to overwrite)`;
|
|
9741
|
-
}
|
|
9742
|
-
return message;
|
|
9743
|
-
}
|
|
9744
|
-
function installClaudeSkill(skill, targetDir, force) {
|
|
9745
|
-
const targetPath = path5.join(targetDir, ".claude", "skills", skill.name);
|
|
9746
|
-
const existedBefore = fs4.existsSync(path5.join(targetPath, "SKILL.md"));
|
|
9747
|
-
const priorManifest = readSkillManifest(targetPath);
|
|
9748
|
-
fs4.mkdirSync(targetPath, { recursive: true });
|
|
9749
|
-
const recon = reconcileSkillTree(skill.bundledPath, targetPath, priorManifest, force);
|
|
9750
|
-
writeSkillManifest(targetPath, buildManifest(skill.name, recon, priorManifest));
|
|
9751
|
-
const changed = recon.added.length + recon.updated.length;
|
|
9752
|
-
const status = !existedBefore ? "installed" : changed > 0 ? "updated" : "already-installed";
|
|
9753
|
-
return {
|
|
9754
|
-
skill: skill.name,
|
|
9755
|
-
client: CodingAgents.claude,
|
|
9756
|
-
targetPath,
|
|
9757
|
-
status,
|
|
9758
|
-
message: buildClaudeMessage(skill.name, status, recon),
|
|
9759
|
-
added: recon.added,
|
|
9760
|
-
updated: recon.updated,
|
|
9761
|
-
unchanged: recon.unchanged,
|
|
9762
|
-
conflicts: recon.conflicts
|
|
9763
|
-
};
|
|
9764
|
-
}
|
|
9765
|
-
function installCodexSymlink(skill, targetDir, force) {
|
|
9766
|
-
const codexPath = path5.join(targetDir, ".codex", "skills", skill.name);
|
|
9767
|
-
const claudePath = path5.join(targetDir, ".claude", "skills", skill.name);
|
|
9768
|
-
const linkTarget = path5.relative(path5.dirname(codexPath), claudePath);
|
|
9769
|
-
fs4.mkdirSync(path5.dirname(codexPath), { recursive: true });
|
|
9770
|
-
let stat;
|
|
9771
|
-
try {
|
|
9772
|
-
stat = fs4.lstatSync(codexPath);
|
|
9773
|
-
} catch {
|
|
9774
|
-
stat = void 0;
|
|
9775
|
-
}
|
|
9776
|
-
if (stat?.isSymbolicLink()) {
|
|
9777
|
-
const existing = fs4.readlinkSync(codexPath);
|
|
9778
|
-
if (existing === linkTarget) {
|
|
9779
|
-
return {
|
|
9780
|
-
skill: skill.name,
|
|
9781
|
-
client: CodingAgents.codex,
|
|
9782
|
-
targetPath: codexPath,
|
|
9783
|
-
status: "already-linked",
|
|
9784
|
-
message: `Already linked: .codex/skills/${skill.name}`
|
|
9785
|
-
};
|
|
9786
|
-
}
|
|
9787
|
-
if (!force) {
|
|
9788
|
-
throw new CliError({
|
|
9789
|
-
code: "VALIDATION_ERROR",
|
|
9790
|
-
message: `.codex/skills/${skill.name} is a symlink pointing elsewhere (${existing}). Pass --force to relink.`,
|
|
9791
|
-
details: { skill: skill.name, targetPath: codexPath, existingTarget: existing },
|
|
9792
|
-
exitCode: 1
|
|
9793
|
-
});
|
|
9794
|
-
}
|
|
9795
|
-
fs4.unlinkSync(codexPath);
|
|
9796
|
-
fs4.symlinkSync(linkTarget, codexPath);
|
|
9797
|
-
return {
|
|
9798
|
-
skill: skill.name,
|
|
9799
|
-
client: CodingAgents.codex,
|
|
9800
|
-
targetPath: codexPath,
|
|
9801
|
-
status: "relinked",
|
|
9802
|
-
message: `Relinked .codex/skills/${skill.name} \u2192 ${linkTarget}`
|
|
9803
|
-
};
|
|
9804
|
-
}
|
|
9805
|
-
if (stat) {
|
|
9806
|
-
if (!force) {
|
|
9807
|
-
throw new CliError({
|
|
9808
|
-
code: "VALIDATION_ERROR",
|
|
9809
|
-
message: `.codex/skills/${skill.name} exists but is not a symlink. Pass --force to replace.`,
|
|
9810
|
-
details: { skill: skill.name, targetPath: codexPath },
|
|
9811
|
-
exitCode: 1
|
|
9812
|
-
});
|
|
9813
|
-
}
|
|
9814
|
-
fs4.rmSync(codexPath, { recursive: true, force: true });
|
|
9815
|
-
}
|
|
9816
|
-
fs4.symlinkSync(linkTarget, codexPath);
|
|
9817
|
-
return {
|
|
9818
|
-
skill: skill.name,
|
|
9819
|
-
client: CodingAgents.codex,
|
|
9820
|
-
targetPath: codexPath,
|
|
9821
|
-
status: stat ? "relinked" : "linked",
|
|
9822
|
-
message: stat ? `Replaced and linked .codex/skills/${skill.name} \u2192 ${linkTarget}` : `Linked .codex/skills/${skill.name} \u2192 ${linkTarget}`
|
|
9823
|
-
};
|
|
9824
|
-
}
|
|
9825
|
-
function buildSummaryMessage(results) {
|
|
9826
|
-
const counts = {};
|
|
9827
|
-
for (const r of results) counts[r.status] = (counts[r.status] ?? 0) + 1;
|
|
9828
|
-
const parts = Object.entries(counts).map(([status, n]) => `${n} ${status}`);
|
|
9829
|
-
let message = `Skills install summary: ${parts.join(", ")}.`;
|
|
9830
|
-
const totalConflicts = results.reduce((sum, r) => sum + (r.conflicts?.length ?? 0), 0);
|
|
9831
|
-
if (totalConflicts > 0) {
|
|
9832
|
-
message += ` ${totalConflicts} file(s) differ from the bundle and were kept \u2014 pass --force to overwrite local edits.`;
|
|
9833
|
-
}
|
|
9834
|
-
return message;
|
|
9835
|
-
}
|
|
9836
|
-
function getBundledSkillSnapshots(pkgDir) {
|
|
9837
|
-
return getBundledSkills(pkgDir).map((skill) => {
|
|
9838
|
-
const files = {};
|
|
9839
|
-
for (const rel of walkRelative(skill.bundledPath)) {
|
|
9840
|
-
files[rel] = sha256File(path5.join(skill.bundledPath, rel));
|
|
9841
|
-
}
|
|
9842
|
-
return { name: skill.name, version: PACKAGE_VERSION, files };
|
|
9843
|
-
});
|
|
9844
|
-
}
|
|
9845
|
-
async function installSkills(opts = {}) {
|
|
9846
|
-
const targetDir = opts.user ? os4.homedir() : path5.resolve(opts.dir ?? process.cwd());
|
|
9847
|
-
const client = opts.client ?? SkillsClients.all;
|
|
9848
|
-
const force = opts.force ?? false;
|
|
9849
|
-
const allSkills = getBundledSkills();
|
|
9850
|
-
const requestedNames = opts.skills && opts.skills.length > 0 ? opts.skills : allSkills.map((s) => s.name);
|
|
9851
|
-
const knownNames = new Set(allSkills.map((s) => s.name));
|
|
9852
|
-
const unknown = requestedNames.filter((n) => !knownNames.has(n));
|
|
9853
|
-
if (unknown.length > 0) {
|
|
9854
|
-
throw new CliError({
|
|
9855
|
-
code: "VALIDATION_ERROR",
|
|
9856
|
-
message: `Unknown skill(s): ${unknown.join(", ")}. Available: ${[...knownNames].join(", ")}`,
|
|
9857
|
-
details: { unknownSkills: unknown, availableSkills: [...knownNames] },
|
|
9858
|
-
exitCode: 1
|
|
9859
|
-
});
|
|
9860
|
-
}
|
|
9861
|
-
const skillsToInstall = allSkills.filter((s) => requestedNames.includes(s.name));
|
|
9862
|
-
fs4.mkdirSync(targetDir, { recursive: true });
|
|
9863
|
-
const results = [];
|
|
9864
|
-
for (const skill of skillsToInstall) {
|
|
9865
|
-
results.push(installClaudeSkill(skill, targetDir, force));
|
|
9866
|
-
if (client !== SkillsClients.claude) {
|
|
9867
|
-
results.push(installCodexSymlink(skill, targetDir, force));
|
|
9868
|
-
}
|
|
9869
|
-
}
|
|
9870
|
-
return {
|
|
9871
|
-
targetDir,
|
|
9872
|
-
results,
|
|
9873
|
-
message: buildSummaryMessage(results)
|
|
9874
|
-
};
|
|
9875
|
-
}
|
|
9876
|
-
async function listSkills(opts = {}) {
|
|
9877
|
-
const skills = getBundledSkills();
|
|
9878
|
-
if (isMachineFormat(opts.format)) {
|
|
9879
|
-
console.log(JSON.stringify({
|
|
9880
|
-
skills: skills.map((s) => ({
|
|
9881
|
-
name: s.name,
|
|
9882
|
-
description: s.description,
|
|
9883
|
-
claudePath: `.claude/skills/${s.name}`,
|
|
9884
|
-
codexPath: `.codex/skills/${s.name}`
|
|
9885
|
-
}))
|
|
9886
|
-
}, null, 2));
|
|
9887
|
-
return;
|
|
9888
|
-
}
|
|
9889
|
-
console.log("Bundled canonry skills:\n");
|
|
9890
|
-
for (const skill of skills) {
|
|
9891
|
-
console.log(` ${skill.name}`);
|
|
9892
|
-
if (skill.description) console.log(` ${skill.description}`);
|
|
9893
|
-
console.log(` Claude: .claude/skills/${skill.name}/`);
|
|
9894
|
-
console.log(` Codex: .codex/skills/${skill.name} (symlink \u2192 ../../.claude/skills/${skill.name})`);
|
|
9895
|
-
console.log();
|
|
9896
|
-
}
|
|
9897
|
-
}
|
|
9898
|
-
function emitInstallSummary(summary, format) {
|
|
9899
|
-
if (isMachineFormat(format)) {
|
|
9900
|
-
console.log(JSON.stringify(summary, null, 2));
|
|
9901
|
-
return;
|
|
9902
|
-
}
|
|
9903
|
-
for (const r of summary.results) console.log(r.message);
|
|
9904
|
-
console.log(`
|
|
9905
|
-
Target: ${summary.targetDir}`);
|
|
9906
|
-
console.log(summary.message);
|
|
9907
|
-
}
|
|
9908
|
-
function getMissingUserSkillsNudge(home, agentPlugin) {
|
|
9909
|
-
if (!home) return null;
|
|
9910
|
-
const skillsBase = path5.join(home, ".claude", "skills");
|
|
9911
|
-
const installed = [];
|
|
9912
|
-
const missing = [];
|
|
9913
|
-
for (const name of BUNDLED_SKILL_NAMES) {
|
|
9914
|
-
const skillFile = path5.join(skillsBase, name, "SKILL.md");
|
|
9915
|
-
if (existsSafe(skillFile)) installed.push(name);
|
|
9916
|
-
else missing.push(name);
|
|
9917
|
-
}
|
|
9918
|
-
if (agentPlugin && agentPlugin.configuredClients.length > 0) {
|
|
9919
|
-
const unverifiedClients = agentPlugin.configuredClients.filter((client) => !agentPlugin.verifiedClients.includes(client));
|
|
9920
|
-
const mismatchedClients = agentPlugin.verifiedClients.filter((client) => agentPlugin.verifiedClientVersions?.[client] !== PACKAGE_VERSION);
|
|
9921
|
-
if (unverifiedClients.length === 0 && mismatchedClients.length === 0) return null;
|
|
9922
|
-
const displayClients = (clients) => clients.map((client) => client === "claude-code" ? "Claude Code" : "Codex").join(" + ");
|
|
9923
|
-
const problems = [];
|
|
9924
|
-
if (unverifiedClients.length > 0) {
|
|
9925
|
-
problems.push(`The Canonry plugin is enabled for ${displayClients(unverifiedClients)}, but its cached manifest and skill assets could not be verified.`);
|
|
9926
|
-
}
|
|
9927
|
-
if (mismatchedClients.length > 0) {
|
|
9928
|
-
const versions = mismatchedClients.map((client) => `${client === "claude-code" ? "Claude Code" : "Codex"} v${agentPlugin.verifiedClientVersions?.[client] ?? "unknown"}`).join(", ");
|
|
9929
|
-
problems.push(`${versions} ${mismatchedClients.length === 1 ? "does" : "do"} not match the running Canonry v${PACKAGE_VERSION}.`);
|
|
9930
|
-
}
|
|
9931
|
-
return {
|
|
9932
|
-
message: `Tip: ${problems.join(" ")} Update or reinstall \`canonry@canonry\` with the affected client plugin manager.`,
|
|
9933
|
-
missing,
|
|
9934
|
-
installed
|
|
9935
|
-
};
|
|
9936
|
-
}
|
|
9937
|
-
if (missing.length === 0) return null;
|
|
9938
|
-
const fix = missing.length === BUNDLED_SKILL_NAMES.length ? "canonry skills install --user" : `canonry skills install ${missing.join(" ")} --user`;
|
|
9939
|
-
return {
|
|
9940
|
-
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.`,
|
|
9941
|
-
missing,
|
|
9942
|
-
installed
|
|
9943
|
-
};
|
|
9944
|
-
}
|
|
9945
|
-
function existsSafe(p) {
|
|
9946
|
-
try {
|
|
9947
|
-
return fs4.existsSync(p);
|
|
9948
|
-
} catch {
|
|
9949
|
-
return false;
|
|
9950
|
-
}
|
|
9951
|
-
}
|
|
9952
|
-
function parseSkillsClient(value) {
|
|
9953
|
-
if (!value) return SkillsClients.all;
|
|
9954
|
-
const parsed = skillsClientSchema.safeParse(value);
|
|
9955
|
-
if (parsed.success) return parsed.data;
|
|
9956
|
-
const allowed = skillsClientSchema.options;
|
|
9957
|
-
throw new CliError({
|
|
9958
|
-
code: "VALIDATION_ERROR",
|
|
9959
|
-
message: `Invalid --client value "${value}". Must be one of: ${allowed.join(", ")}`,
|
|
9960
|
-
details: { flag: "client", value, allowed },
|
|
9961
|
-
exitCode: 1
|
|
9962
|
-
});
|
|
9963
|
-
}
|
|
9964
|
-
|
|
9965
9614
|
// src/provider-registry.ts
|
|
9966
9615
|
var ProviderRegistry = class {
|
|
9967
9616
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -10014,7 +9663,7 @@ var ProviderRegistry = class {
|
|
|
10014
9663
|
};
|
|
10015
9664
|
|
|
10016
9665
|
// src/scheduler.ts
|
|
10017
|
-
import
|
|
9666
|
+
import crypto18 from "crypto";
|
|
10018
9667
|
import cron from "node-cron";
|
|
10019
9668
|
import { and as and14, eq as eq17, inArray as inArray6, notExists, sql as sql8 } from "drizzle-orm";
|
|
10020
9669
|
var log13 = createLogger("Scheduler");
|
|
@@ -10057,7 +9706,7 @@ var Scheduler = class {
|
|
|
10057
9706
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10058
9707
|
for (const project of projectsWithoutHealth) {
|
|
10059
9708
|
this.db.insert(schedules).values({
|
|
10060
|
-
id:
|
|
9709
|
+
id: crypto18.randomUUID(),
|
|
10061
9710
|
projectId: project.id,
|
|
10062
9711
|
kind: SchedulableRunKinds.doctor,
|
|
10063
9712
|
cronExpr: DEFAULT_HEALTH_CRON,
|
|
@@ -10216,7 +9865,7 @@ var Scheduler = class {
|
|
|
10216
9865
|
log13.warn("gbp-sync.no-callback", { scheduleId, projectId, msg: "host did not register onGbpSyncRequested" });
|
|
10217
9866
|
return;
|
|
10218
9867
|
}
|
|
10219
|
-
const runId2 =
|
|
9868
|
+
const runId2 = crypto18.randomUUID();
|
|
10220
9869
|
this.db.insert(runs).values({
|
|
10221
9870
|
id: runId2,
|
|
10222
9871
|
projectId,
|
|
@@ -10249,7 +9898,7 @@ var Scheduler = class {
|
|
|
10249
9898
|
this.db.update(schedules).set({ nextRunAt, updatedAt: now }).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
10250
9899
|
return;
|
|
10251
9900
|
}
|
|
10252
|
-
const runId2 =
|
|
9901
|
+
const runId2 = crypto18.randomUUID();
|
|
10253
9902
|
this.db.insert(runs).values({
|
|
10254
9903
|
id: runId2,
|
|
10255
9904
|
projectId,
|
|
@@ -10324,7 +9973,7 @@ var Scheduler = class {
|
|
|
10324
9973
|
this.db.update(schedules).set({ nextRunAt, updatedAt: now }).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
10325
9974
|
return;
|
|
10326
9975
|
}
|
|
10327
|
-
const runId2 =
|
|
9976
|
+
const runId2 = crypto18.randomUUID();
|
|
10328
9977
|
const effectiveRequest = normalizeSiteAuditRunRequest({});
|
|
10329
9978
|
this.db.transaction((tx) => {
|
|
10330
9979
|
tx.insert(runs).values({
|
|
@@ -10422,7 +10071,7 @@ async function refreshAllIntegrations(client, projectName) {
|
|
|
10422
10071
|
|
|
10423
10072
|
// src/notifier.ts
|
|
10424
10073
|
import { eq as eq18, desc as desc7, and as and15, inArray as inArray7, or as or2 } from "drizzle-orm";
|
|
10425
|
-
import
|
|
10074
|
+
import crypto19 from "crypto";
|
|
10426
10075
|
var log15 = createLogger("Notifier");
|
|
10427
10076
|
var Notifier = class {
|
|
10428
10077
|
db;
|
|
@@ -10748,7 +10397,7 @@ var Notifier = class {
|
|
|
10748
10397
|
}
|
|
10749
10398
|
logDelivery(projectId, notificationId, event, status, error) {
|
|
10750
10399
|
this.db.insert(auditLog).values({
|
|
10751
|
-
id:
|
|
10400
|
+
id: crypto19.randomUUID(),
|
|
10752
10401
|
projectId,
|
|
10753
10402
|
actor: "scheduler",
|
|
10754
10403
|
action: `notification.${status}`,
|
|
@@ -10910,12 +10559,12 @@ function analysisResultFromInsights(insights2) {
|
|
|
10910
10559
|
}
|
|
10911
10560
|
|
|
10912
10561
|
// src/agent/session-registry.ts
|
|
10913
|
-
import
|
|
10562
|
+
import crypto23 from "crypto";
|
|
10914
10563
|
import { eq as eq21 } from "drizzle-orm";
|
|
10915
10564
|
|
|
10916
10565
|
// src/agent/session.ts
|
|
10917
|
-
import
|
|
10918
|
-
import
|
|
10566
|
+
import fs6 from "fs";
|
|
10567
|
+
import path7 from "path";
|
|
10919
10568
|
import { Agent } from "@mariozechner/pi-agent-core";
|
|
10920
10569
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
10921
10570
|
|
|
@@ -11158,26 +10807,26 @@ function buildAgentProvidersResponse(config) {
|
|
|
11158
10807
|
}
|
|
11159
10808
|
|
|
11160
10809
|
// src/agent/skill-paths.ts
|
|
11161
|
-
import
|
|
11162
|
-
import
|
|
11163
|
-
import { fileURLToPath
|
|
10810
|
+
import fs4 from "fs";
|
|
10811
|
+
import path5 from "path";
|
|
10812
|
+
import { fileURLToPath } from "url";
|
|
11164
10813
|
function resolveAeroSkillDir(pkgDir) {
|
|
11165
|
-
const here = pkgDir ??
|
|
10814
|
+
const here = pkgDir ?? path5.dirname(fileURLToPath(import.meta.url));
|
|
11166
10815
|
const candidates = [
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
10816
|
+
path5.join(here, "../assets/agent-workspace/skills/aero"),
|
|
10817
|
+
path5.join(here, "../../assets/agent-workspace/skills/aero"),
|
|
10818
|
+
path5.join(here, "../../../../skills/aero")
|
|
11170
10819
|
];
|
|
11171
10820
|
for (const candidate of candidates) {
|
|
11172
|
-
if (
|
|
10821
|
+
if (fs4.existsSync(path5.join(candidate, "SKILL.md"))) return candidate;
|
|
11173
10822
|
}
|
|
11174
10823
|
throw new Error(`Aero skill not found. Searched:
|
|
11175
10824
|
${candidates.join("\n ")}`);
|
|
11176
10825
|
}
|
|
11177
10826
|
|
|
11178
10827
|
// src/agent/skill-tools.ts
|
|
11179
|
-
import
|
|
11180
|
-
import
|
|
10828
|
+
import fs5 from "fs";
|
|
10829
|
+
import path6 from "path";
|
|
11181
10830
|
import { Type } from "@sinclair/typebox";
|
|
11182
10831
|
var MAX_DOC_CHARS = 2e4;
|
|
11183
10832
|
function textResult(details) {
|
|
@@ -11186,7 +10835,7 @@ function textResult(details) {
|
|
|
11186
10835
|
details
|
|
11187
10836
|
};
|
|
11188
10837
|
}
|
|
11189
|
-
function
|
|
10838
|
+
function parseDescription(body) {
|
|
11190
10839
|
if (!body.startsWith("---")) return "(no description)";
|
|
11191
10840
|
const end = body.indexOf("\n---", 3);
|
|
11192
10841
|
if (end === -1) return "(no description)";
|
|
@@ -11198,16 +10847,16 @@ function parseDescription2(body) {
|
|
|
11198
10847
|
return "(no description)";
|
|
11199
10848
|
}
|
|
11200
10849
|
function scanSkillDocs(skillDir) {
|
|
11201
|
-
const refsDir =
|
|
11202
|
-
if (!
|
|
10850
|
+
const refsDir = path6.join(skillDir ?? resolveAeroSkillDir(), "references");
|
|
10851
|
+
if (!fs5.existsSync(refsDir)) return [];
|
|
11203
10852
|
const entries = [];
|
|
11204
|
-
for (const file of
|
|
10853
|
+
for (const file of fs5.readdirSync(refsDir)) {
|
|
11205
10854
|
if (!file.endsWith(".md")) continue;
|
|
11206
|
-
const filePath =
|
|
11207
|
-
const body =
|
|
10855
|
+
const filePath = path6.join(refsDir, file);
|
|
10856
|
+
const body = fs5.readFileSync(filePath, "utf-8");
|
|
11208
10857
|
entries.push({
|
|
11209
10858
|
slug: file.replace(/\.md$/, ""),
|
|
11210
|
-
description:
|
|
10859
|
+
description: parseDescription(body),
|
|
11211
10860
|
bytes: Buffer.byteLength(body, "utf-8")
|
|
11212
10861
|
});
|
|
11213
10862
|
}
|
|
@@ -11247,8 +10896,8 @@ function buildReadSkillDocTool() {
|
|
|
11247
10896
|
availableSlugs: docs.map((d) => d.slug)
|
|
11248
10897
|
});
|
|
11249
10898
|
}
|
|
11250
|
-
const filePath =
|
|
11251
|
-
const content =
|
|
10899
|
+
const filePath = path6.join(skillDir, "references", `${match.slug}.md`);
|
|
10900
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
11252
10901
|
if (content.length > MAX_DOC_CHARS) {
|
|
11253
10902
|
return textResult({
|
|
11254
10903
|
slug: match.slug,
|
|
@@ -11654,7 +11303,7 @@ function buildAeroStateTools(ctx, opts = {}) {
|
|
|
11654
11303
|
}
|
|
11655
11304
|
|
|
11656
11305
|
// src/agent/llm-usage.ts
|
|
11657
|
-
import
|
|
11306
|
+
import crypto20 from "crypto";
|
|
11658
11307
|
var AeroLlmUsageFeatures = {
|
|
11659
11308
|
turn: "aero.turn"
|
|
11660
11309
|
};
|
|
@@ -11673,7 +11322,7 @@ function recordLlmUsageEvent(args) {
|
|
|
11673
11322
|
const usage = args.message.usage;
|
|
11674
11323
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11675
11324
|
args.db.insert(llmUsageEvents).values({
|
|
11676
|
-
id:
|
|
11325
|
+
id: crypto20.randomUUID(),
|
|
11677
11326
|
projectId: args.projectId,
|
|
11678
11327
|
runId: args.runId,
|
|
11679
11328
|
agentSessionId: args.agentSessionId,
|
|
@@ -11749,7 +11398,7 @@ function splitAeroAnthropicSystemCachePayload(payload, model) {
|
|
|
11749
11398
|
}
|
|
11750
11399
|
|
|
11751
11400
|
// src/agent/tool-usage.ts
|
|
11752
|
-
import
|
|
11401
|
+
import crypto21 from "crypto";
|
|
11753
11402
|
var AeroToolEventStatuses = {
|
|
11754
11403
|
success: "success",
|
|
11755
11404
|
error: "error"
|
|
@@ -11812,7 +11461,7 @@ function createAeroToolUsageHooks(args) {
|
|
|
11812
11461
|
function recordAgentToolEvent(args) {
|
|
11813
11462
|
try {
|
|
11814
11463
|
args.db.insert(agentToolEvents).values({
|
|
11815
|
-
id:
|
|
11464
|
+
id: crypto21.randomUUID(),
|
|
11816
11465
|
projectId: args.projectId,
|
|
11817
11466
|
agentSessionId: args.agentSessionId,
|
|
11818
11467
|
toolCallId: args.toolCallId,
|
|
@@ -11843,9 +11492,9 @@ function ensureBuiltinsRegistered() {
|
|
|
11843
11492
|
}
|
|
11844
11493
|
function loadAeroSystemPrompt(pkgDir) {
|
|
11845
11494
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
11846
|
-
const skillBody =
|
|
11847
|
-
const soulPath =
|
|
11848
|
-
const base =
|
|
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()}
|
|
11849
11498
|
|
|
11850
11499
|
---
|
|
11851
11500
|
|
|
@@ -11858,7 +11507,7 @@ function appendSystemPromptExtras(base, env = process.env) {
|
|
|
11858
11507
|
const filePath = env.AERO_SYSTEM_PROMPT_FILE?.trim();
|
|
11859
11508
|
if (filePath) {
|
|
11860
11509
|
try {
|
|
11861
|
-
fileBody =
|
|
11510
|
+
fileBody = fs6.readFileSync(filePath, "utf-8").trim();
|
|
11862
11511
|
} catch {
|
|
11863
11512
|
fileBody = "";
|
|
11864
11513
|
}
|
|
@@ -12039,7 +11688,7 @@ async function loadExternalMcpTools(servers, opts = {}) {
|
|
|
12039
11688
|
}
|
|
12040
11689
|
|
|
12041
11690
|
// src/agent/memory-store.ts
|
|
12042
|
-
import
|
|
11691
|
+
import crypto22 from "crypto";
|
|
12043
11692
|
import { and as and16, desc as desc8, eq as eq20, like, sql as sql9 } from "drizzle-orm";
|
|
12044
11693
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
12045
11694
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
@@ -12068,7 +11717,7 @@ function upsertMemoryEntry(db, args) {
|
|
|
12068
11717
|
throw new Error(`memory key prefix "${COMPACTION_KEY_PREFIX}" is reserved for compaction notes`);
|
|
12069
11718
|
}
|
|
12070
11719
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12071
|
-
const id =
|
|
11720
|
+
const id = crypto22.randomUUID();
|
|
12072
11721
|
db.insert(agentMemory).values({
|
|
12073
11722
|
id,
|
|
12074
11723
|
projectId: args.projectId,
|
|
@@ -12105,7 +11754,7 @@ function writeCompactionNote(db, args) {
|
|
|
12105
11754
|
}
|
|
12106
11755
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12107
11756
|
const key = `${COMPACTION_KEY_PREFIX}${args.sessionId}:${now}`;
|
|
12108
|
-
const id =
|
|
11757
|
+
const id = crypto22.randomUUID();
|
|
12109
11758
|
let inserted;
|
|
12110
11759
|
db.transaction((tx) => {
|
|
12111
11760
|
tx.insert(agentMemory).values({
|
|
@@ -12384,7 +12033,7 @@ var SessionRegistry = class {
|
|
|
12384
12033
|
}
|
|
12385
12034
|
const { provider, modelId } = resolveSessionProviderAndModel(this.opts.config, preferences);
|
|
12386
12035
|
const systemPrompt = loadAeroSystemPrompt();
|
|
12387
|
-
const sessionId =
|
|
12036
|
+
const sessionId = crypto23.randomUUID();
|
|
12388
12037
|
const agent = createAeroSession({
|
|
12389
12038
|
projectName,
|
|
12390
12039
|
client: this.opts.client,
|
|
@@ -12763,7 +12412,7 @@ ${lines.join("\n")}
|
|
|
12763
12412
|
insertRow(params) {
|
|
12764
12413
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12765
12414
|
this.opts.db.insert(agentSessions).values({
|
|
12766
|
-
id: params.id ??
|
|
12415
|
+
id: params.id ?? crypto23.randomUUID(),
|
|
12767
12416
|
projectId: params.projectId,
|
|
12768
12417
|
systemPrompt: params.systemPrompt,
|
|
12769
12418
|
modelProvider: params.provider ?? params.modelProvider ?? AgentProviderIds.claude,
|
|
@@ -13151,13 +12800,13 @@ var USER_AGENT2 = "Canonry/1.0 (site-analysis)";
|
|
|
13151
12800
|
function fetchWithPinnedAddress(target) {
|
|
13152
12801
|
return new Promise((resolve) => {
|
|
13153
12802
|
const port = target.url.port ? Number(target.url.port) : 443;
|
|
13154
|
-
const
|
|
12803
|
+
const path9 = target.url.pathname + target.url.search;
|
|
13155
12804
|
const req = https2.request(
|
|
13156
12805
|
{
|
|
13157
12806
|
hostname: target.address,
|
|
13158
12807
|
family: target.family,
|
|
13159
12808
|
port,
|
|
13160
|
-
path:
|
|
12809
|
+
path: path9,
|
|
13161
12810
|
method: "GET",
|
|
13162
12811
|
timeout: FETCH_TIMEOUT_MS2,
|
|
13163
12812
|
servername: target.url.hostname,
|
|
@@ -13946,14 +13595,14 @@ function summarizeProviderConfig(config) {
|
|
|
13946
13595
|
};
|
|
13947
13596
|
}
|
|
13948
13597
|
function hashApiKey(key) {
|
|
13949
|
-
return
|
|
13598
|
+
return crypto24.createHash("sha256").update(key).digest("hex");
|
|
13950
13599
|
}
|
|
13951
13600
|
var DASHBOARD_SCRYPT_KEYLEN = 64;
|
|
13952
13601
|
var DASHBOARD_SCRYPT_COST = 1 << 15;
|
|
13953
13602
|
var DASHBOARD_SCRYPT_MAXMEM = 64 * 1024 * 1024;
|
|
13954
13603
|
function hashDashboardPassword(password) {
|
|
13955
|
-
const salt =
|
|
13956
|
-
const derived =
|
|
13604
|
+
const salt = crypto24.randomBytes(16);
|
|
13605
|
+
const derived = crypto24.scryptSync(password, salt, DASHBOARD_SCRYPT_KEYLEN, {
|
|
13957
13606
|
N: DASHBOARD_SCRYPT_COST,
|
|
13958
13607
|
maxmem: DASHBOARD_SCRYPT_MAXMEM
|
|
13959
13608
|
});
|
|
@@ -13974,14 +13623,14 @@ function verifyDashboardPassword(password, storedHash) {
|
|
|
13974
13623
|
} catch {
|
|
13975
13624
|
return { ok: false, needsRehash: false };
|
|
13976
13625
|
}
|
|
13977
|
-
const derived =
|
|
13626
|
+
const derived = crypto24.scryptSync(password, salt, expected.length, {
|
|
13978
13627
|
N: DASHBOARD_SCRYPT_COST,
|
|
13979
13628
|
maxmem: DASHBOARD_SCRYPT_MAXMEM
|
|
13980
13629
|
});
|
|
13981
13630
|
if (derived.length !== expected.length)
|
|
13982
13631
|
return { ok: false, needsRehash: false };
|
|
13983
13632
|
return {
|
|
13984
|
-
ok:
|
|
13633
|
+
ok: crypto24.timingSafeEqual(derived, expected),
|
|
13985
13634
|
needsRehash: false
|
|
13986
13635
|
};
|
|
13987
13636
|
}
|
|
@@ -13990,7 +13639,7 @@ function verifyDashboardPassword(password, storedHash) {
|
|
|
13990
13639
|
const expected = Buffer.from(storedHash, "hex");
|
|
13991
13640
|
if (candidate.length !== expected.length)
|
|
13992
13641
|
return { ok: false, needsRehash: false };
|
|
13993
|
-
const ok =
|
|
13642
|
+
const ok = crypto24.timingSafeEqual(candidate, expected);
|
|
13994
13643
|
return { ok, needsRehash: ok };
|
|
13995
13644
|
}
|
|
13996
13645
|
return { ok: false, needsRehash: false };
|
|
@@ -14221,8 +13870,8 @@ async function createServer(opts) {
|
|
|
14221
13870
|
);
|
|
14222
13871
|
jobRunner.onRunCompleted = (runId, projectId) => runCoordinator.onRunCompleted(runId, projectId);
|
|
14223
13872
|
const snapshotService = new SnapshotService(registry);
|
|
14224
|
-
const orphanedOpenClawDir =
|
|
14225
|
-
if (
|
|
13873
|
+
const orphanedOpenClawDir = path8.join(os4.homedir(), ".openclaw-aero");
|
|
13874
|
+
if (fs7.existsSync(orphanedOpenClawDir)) {
|
|
14226
13875
|
app.log.warn(
|
|
14227
13876
|
{ path: orphanedOpenClawDir },
|
|
14228
13877
|
"OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
|
|
@@ -14759,7 +14408,7 @@ async function createServer(opts) {
|
|
|
14759
14408
|
return removed;
|
|
14760
14409
|
}
|
|
14761
14410
|
};
|
|
14762
|
-
const googleStateSecret = process.env.GOOGLE_STATE_SECRET ??
|
|
14411
|
+
const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto24.randomBytes(32).toString("hex");
|
|
14763
14412
|
const googleConnectionStore = {
|
|
14764
14413
|
listConnections: (domain) => listGoogleConnections(opts.config, domain),
|
|
14765
14414
|
getConnection: (domain, connectionType) => getGoogleConnection(opts.config, domain, connectionType),
|
|
@@ -14839,7 +14488,7 @@ async function createServer(opts) {
|
|
|
14839
14488
|
if (!existing) {
|
|
14840
14489
|
const prefix = opts.config.apiKey.slice(0, 12);
|
|
14841
14490
|
opts.db.insert(apiKeys).values({
|
|
14842
|
-
id: `key_${
|
|
14491
|
+
id: `key_${crypto24.randomBytes(8).toString("hex")}`,
|
|
14843
14492
|
name: "default",
|
|
14844
14493
|
keyHash,
|
|
14845
14494
|
keyPrefix: prefix,
|
|
@@ -14863,7 +14512,7 @@ async function createServer(opts) {
|
|
|
14863
14512
|
};
|
|
14864
14513
|
const createSession = (apiKeyId) => {
|
|
14865
14514
|
pruneExpiredSessions();
|
|
14866
|
-
const sessionId =
|
|
14515
|
+
const sessionId = crypto24.randomBytes(32).toString("hex");
|
|
14867
14516
|
sessions.set(sessionId, {
|
|
14868
14517
|
apiKeyId,
|
|
14869
14518
|
expiresAt: Date.now() + SESSION_TTL_MS
|
|
@@ -15111,7 +14760,7 @@ async function createServer(opts) {
|
|
|
15111
14760
|
const configPath = getConfigPath();
|
|
15112
14761
|
return {
|
|
15113
14762
|
databasePath: opts.config.database,
|
|
15114
|
-
configPath:
|
|
14763
|
+
configPath: fs7.existsSync(configPath) ? configPath : null
|
|
15115
14764
|
};
|
|
15116
14765
|
})(),
|
|
15117
14766
|
// Snapshot the bundled skill trees (version + file hashes) so the
|
|
@@ -15223,7 +14872,7 @@ async function createServer(opts) {
|
|
|
15223
14872
|
deps: {
|
|
15224
14873
|
enqueueAutoExtract: ({ projectId, release: r }) => {
|
|
15225
14874
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15226
|
-
const runId =
|
|
14875
|
+
const runId = crypto24.randomUUID();
|
|
15227
14876
|
opts.db.insert(runs).values({
|
|
15228
14877
|
id: runId,
|
|
15229
14878
|
projectId,
|
|
@@ -15458,7 +15107,7 @@ async function createServer(opts) {
|
|
|
15458
15107
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15459
15108
|
opts.db.insert(auditLog).values(
|
|
15460
15109
|
targetProjectIds.map((projectId) => ({
|
|
15461
|
-
id:
|
|
15110
|
+
id: crypto24.randomUUID(),
|
|
15462
15111
|
projectId,
|
|
15463
15112
|
actor: "api",
|
|
15464
15113
|
action: existing ? "provider.updated" : "provider.created",
|
|
@@ -15617,10 +15266,10 @@ async function createServer(opts) {
|
|
|
15617
15266
|
return snapshotService.createReport(input);
|
|
15618
15267
|
}
|
|
15619
15268
|
});
|
|
15620
|
-
const dirname =
|
|
15621
|
-
const assetsDir = opts.assetsDir ??
|
|
15622
|
-
if (
|
|
15623
|
-
const indexPath =
|
|
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");
|
|
15624
15273
|
const injectConfig = (html, projectTabsOverride, themeOverride, renderTokenOverride) => {
|
|
15625
15274
|
const clientConfig = {};
|
|
15626
15275
|
if (basePath) clientConfig.basePath = basePath;
|
|
@@ -15675,8 +15324,8 @@ async function createServer(opts) {
|
|
|
15675
15324
|
// Without this, the browser hits the server for every JS chunk on
|
|
15676
15325
|
// every page load, defeating most of the dashboard's first-paint
|
|
15677
15326
|
// budget.
|
|
15678
|
-
setHeaders: (res,
|
|
15679
|
-
if (
|
|
15327
|
+
setHeaders: (res, path9) => {
|
|
15328
|
+
if (path9.endsWith(".html")) {
|
|
15680
15329
|
res.setHeader("Cache-Control", "no-cache, must-revalidate");
|
|
15681
15330
|
} else {
|
|
15682
15331
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
@@ -15684,8 +15333,8 @@ async function createServer(opts) {
|
|
|
15684
15333
|
}
|
|
15685
15334
|
});
|
|
15686
15335
|
const serveIndex = (_request, reply) => {
|
|
15687
|
-
if (
|
|
15688
|
-
const html =
|
|
15336
|
+
if (fs7.existsSync(indexPath)) {
|
|
15337
|
+
const html = fs7.readFileSync(indexPath, "utf-8");
|
|
15689
15338
|
return sendSpaDocument(reply, html);
|
|
15690
15339
|
}
|
|
15691
15340
|
return reply.status(404).send({ error: "Dashboard not built" });
|
|
@@ -15706,8 +15355,8 @@ async function createServer(opts) {
|
|
|
15706
15355
|
if (basePath && !url.startsWith(basePath)) {
|
|
15707
15356
|
return reply.status(404).send({ error: "Not found", path: request.url });
|
|
15708
15357
|
}
|
|
15709
|
-
if (
|
|
15710
|
-
const html =
|
|
15358
|
+
if (fs7.existsSync(indexPath)) {
|
|
15359
|
+
const html = fs7.readFileSync(indexPath, "utf-8");
|
|
15711
15360
|
return sendSpaDocument(reply, html);
|
|
15712
15361
|
}
|
|
15713
15362
|
return reply.status(404).send({ error: "Not found" });
|
|
@@ -15814,11 +15463,6 @@ export {
|
|
|
15814
15463
|
backfillTrafficClassificationCommand,
|
|
15815
15464
|
getCloudflareTrafficConnectionBySourceId,
|
|
15816
15465
|
setGoogleAuthConfig,
|
|
15817
|
-
installSkills,
|
|
15818
|
-
listSkills,
|
|
15819
|
-
emitInstallSummary,
|
|
15820
|
-
getMissingUserSkillsNudge,
|
|
15821
|
-
parseSkillsClient,
|
|
15822
15466
|
formatAuditFactorScore,
|
|
15823
15467
|
checkLatestVersionForCli,
|
|
15824
15468
|
listAgentProviders,
|