@ainyc/canonry 5.1.2 → 5.1.4
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/assets/agent-workspace/skills/aero/SKILL.md +43 -9
- package/assets/agent-workspace/skills/aero/references/agent-operations.md +231 -0
- package/assets/agent-workspace/skills/aero/references/orchestration.md +11 -5
- package/assets/agent-workspace/skills/aero/references/portfolio-analysis.md +93 -0
- package/assets/agent-workspace/skills/aero/references/reporting.md +10 -1
- package/assets/agent-workspace/skills/aero/references/site-health.md +104 -0
- package/assets/agent-workspace/skills/aero/soul.md +5 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +2 -0
- package/dist/{chunk-BS4ZC7FG.js → chunk-3KXI4C3S.js} +172 -79
- package/dist/{chunk-5K2NUQOV.js → chunk-AEE5DGTE.js} +59 -4
- package/dist/{chunk-WSYJ4IT7.js → chunk-EBUX3C5H.js} +68 -1
- package/dist/{chunk-NKEKDWGX.js → chunk-KJM4DRZN.js} +2 -2
- package/dist/{chunk-5ZIUROAQ.js → chunk-MMSPU72Z.js} +65 -1
- package/dist/cli.js +13 -16
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-D2HY2S5F.js → intelligence-service-25NQCETC.js} +2 -2
- package/dist/mcp.js +47 -6
- package/package.json +11 -11
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
resolveOperatorApiKeyIds,
|
|
18
18
|
runWithUsageTags,
|
|
19
19
|
saveConfigPatch
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-AEE5DGTE.js";
|
|
21
21
|
import {
|
|
22
22
|
CC_CACHE_DIR,
|
|
23
23
|
DUCKDB_SPEC,
|
|
@@ -168,7 +168,7 @@ import {
|
|
|
168
168
|
siteCrawlSnapshots,
|
|
169
169
|
toAlertView,
|
|
170
170
|
usageCounters
|
|
171
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-EBUX3C5H.js";
|
|
172
172
|
import {
|
|
173
173
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
174
174
|
AGENT_NONE,
|
|
@@ -179,6 +179,7 @@ import {
|
|
|
179
179
|
AdsCampaignBiddingTypes,
|
|
180
180
|
AgentProviderIds,
|
|
181
181
|
BacklinkSources,
|
|
182
|
+
CANONRY_NPM_PACKAGE_URL,
|
|
182
183
|
CITED_URL_CAPTURE_VERSION,
|
|
183
184
|
CcReleaseSyncStatuses,
|
|
184
185
|
DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
|
|
@@ -239,6 +240,7 @@ import {
|
|
|
239
240
|
classifyProviderErrorMessages,
|
|
240
241
|
classifyTemplateLinkEdge,
|
|
241
242
|
cloudflareQueueNameSchema,
|
|
243
|
+
compareSemver,
|
|
242
244
|
computeBacklinkSummaryMetrics,
|
|
243
245
|
contentActionLabel,
|
|
244
246
|
contentBriefDtoSchema,
|
|
@@ -279,9 +281,11 @@ import {
|
|
|
279
281
|
isAgentProviderId,
|
|
280
282
|
isBrowserProvider,
|
|
281
283
|
isGhostTelemetryEvent,
|
|
284
|
+
isInstallMethod,
|
|
282
285
|
isReadOnlyKey,
|
|
283
286
|
isRetryableHttpError,
|
|
284
287
|
isSelfLink,
|
|
288
|
+
isStrictSemver,
|
|
285
289
|
isVertexGroundingRedirect,
|
|
286
290
|
mapWithConcurrency,
|
|
287
291
|
maskTelemetryAnonymousId,
|
|
@@ -313,11 +317,14 @@ import {
|
|
|
313
317
|
templateLinkUbiquityAvailable,
|
|
314
318
|
textContainsBrandAlias,
|
|
315
319
|
textContainsDomain,
|
|
320
|
+
updateCheckEnvOptOut,
|
|
321
|
+
upgradeCaveatFor,
|
|
322
|
+
upgradeCommandFor,
|
|
316
323
|
usageSurfaceSchema,
|
|
317
324
|
validationError,
|
|
318
325
|
winnabilityClassLabel,
|
|
319
326
|
withRetry
|
|
320
|
-
} from "./chunk-
|
|
327
|
+
} from "./chunk-MMSPU72Z.js";
|
|
321
328
|
|
|
322
329
|
// src/runtime-context.ts
|
|
323
330
|
function cliRuntimeContext(env = process.env, stdio = process) {
|
|
@@ -569,47 +576,46 @@ function deliverEvent(event, properties, options, delivery = {}) {
|
|
|
569
576
|
}
|
|
570
577
|
|
|
571
578
|
// src/update-check.ts
|
|
579
|
+
import fs from "fs";
|
|
572
580
|
import { createRequire as createRequire2 } from "module";
|
|
581
|
+
import { fileURLToPath } from "url";
|
|
573
582
|
var _require2 = createRequire2(import.meta.url);
|
|
574
583
|
var { version: PKG_VERSION } = _require2("../package.json");
|
|
575
584
|
var PKG_NAME = "@canonry/canonry";
|
|
576
585
|
var NPM_DIST_TAGS_URL = `https://registry.npmjs.org/-/package/${PKG_NAME}/dist-tags`;
|
|
577
|
-
var NPM_PACKAGE_URL =
|
|
586
|
+
var NPM_PACKAGE_URL = CANONRY_NPM_PACKAGE_URL;
|
|
578
587
|
var FETCH_TIMEOUT_MS = 1500;
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (
|
|
583
|
-
|
|
588
|
+
var CONTAINER_MARKERS = ["/.dockerenv", "/run/.containerenv"];
|
|
589
|
+
function detectInstallMethod(opts) {
|
|
590
|
+
const declared = (opts?.env ?? process.env).CANONRY_INSTALL_METHOD;
|
|
591
|
+
if (isInstallMethod(declared)) return declared;
|
|
592
|
+
let modulePath = opts?.modulePath ?? fileURLToPath(import.meta.url);
|
|
584
593
|
try {
|
|
585
|
-
|
|
586
|
-
return raw?.updateCheck !== false;
|
|
594
|
+
modulePath = fs.realpathSync(modulePath);
|
|
587
595
|
} catch {
|
|
588
|
-
return true;
|
|
589
596
|
}
|
|
597
|
+
if (modulePath.replace(/\\/g, "/").includes("/Cellar/canonry/")) return "homebrew";
|
|
598
|
+
const exists = opts?.exists ?? fs.existsSync;
|
|
599
|
+
if (CONTAINER_MARKERS.some((marker) => exists(marker))) return "docker";
|
|
600
|
+
return "npm";
|
|
590
601
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
if (!pa || !pb) return 0;
|
|
608
|
-
for (let i = 0; i < 3; i++) {
|
|
609
|
-
if (pa[i] > pb[i]) return 1;
|
|
610
|
-
if (pa[i] < pb[i]) return -1;
|
|
602
|
+
var detectedInstallMethod;
|
|
603
|
+
function currentInstallMethod() {
|
|
604
|
+
detectedInstallMethod ??= detectInstallMethod();
|
|
605
|
+
return detectedInstallMethod;
|
|
606
|
+
}
|
|
607
|
+
function isUpdateCheckEnabled() {
|
|
608
|
+
return updateCheckDisabledReason() === null;
|
|
609
|
+
}
|
|
610
|
+
function updateCheckDisabledReason() {
|
|
611
|
+
const envOptOut = updateCheckEnvOptOut(process.env);
|
|
612
|
+
if (envOptOut) return envOptOut;
|
|
613
|
+
if (!configExists()) return null;
|
|
614
|
+
try {
|
|
615
|
+
return loadConfigRaw()?.updateCheck === false ? "config" : null;
|
|
616
|
+
} catch {
|
|
617
|
+
return null;
|
|
611
618
|
}
|
|
612
|
-
return 0;
|
|
613
619
|
}
|
|
614
620
|
async function fetchLatestVersion(opts) {
|
|
615
621
|
const controller = new AbortController();
|
|
@@ -622,7 +628,7 @@ async function fetchLatestVersion(opts) {
|
|
|
622
628
|
});
|
|
623
629
|
if (!res.ok) return null;
|
|
624
630
|
const data = await res.json();
|
|
625
|
-
if (typeof data.latest !== "string") return null;
|
|
631
|
+
if (typeof data.latest !== "string" || !isStrictSemver(data.latest)) return null;
|
|
626
632
|
return data.latest;
|
|
627
633
|
} catch {
|
|
628
634
|
return null;
|
|
@@ -630,13 +636,15 @@ async function fetchLatestVersion(opts) {
|
|
|
630
636
|
clearTimeout(timeout);
|
|
631
637
|
}
|
|
632
638
|
}
|
|
633
|
-
function buildUpdateAvailable(current, latest) {
|
|
639
|
+
function buildUpdateAvailable(current, latest, installMethod = currentInstallMethod()) {
|
|
640
|
+
if (!isStrictSemver(latest)) return null;
|
|
634
641
|
if (compareSemver(latest, current) <= 0) return null;
|
|
635
642
|
return {
|
|
636
643
|
current,
|
|
637
644
|
latest,
|
|
638
645
|
url: NPM_PACKAGE_URL,
|
|
639
|
-
upgradeCommand:
|
|
646
|
+
upgradeCommand: upgradeCommandFor(installMethod),
|
|
647
|
+
installMethod
|
|
640
648
|
};
|
|
641
649
|
}
|
|
642
650
|
async function checkLatestVersionForCli(opts) {
|
|
@@ -674,6 +682,45 @@ async function checkLatestVersionForCli(opts) {
|
|
|
674
682
|
}
|
|
675
683
|
return buildUpdateAvailable(PKG_VERSION, latest);
|
|
676
684
|
}
|
|
685
|
+
function readCachedUpdateAvailable() {
|
|
686
|
+
if (!isUpdateCheckEnabled()) return null;
|
|
687
|
+
if (!configExists()) return null;
|
|
688
|
+
try {
|
|
689
|
+
const cachedLatest = loadConfigRaw()?.lastKnownLatestVersion;
|
|
690
|
+
if (typeof cachedLatest !== "string") return null;
|
|
691
|
+
return buildUpdateAvailable(PKG_VERSION, cachedLatest);
|
|
692
|
+
} catch {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
var UPDATE_AVAILABLE_NOTICE_CODE = "UPDATE_AVAILABLE";
|
|
697
|
+
function formatUpdateNotice(update, opts) {
|
|
698
|
+
const caveat = upgradeCaveatFor(update.installMethod);
|
|
699
|
+
if (opts.format === "json" || opts.format === "jsonl") {
|
|
700
|
+
return `${JSON.stringify({
|
|
701
|
+
notice: {
|
|
702
|
+
code: UPDATE_AVAILABLE_NOTICE_CODE,
|
|
703
|
+
current: update.current,
|
|
704
|
+
latest: update.latest,
|
|
705
|
+
installMethod: update.installMethod,
|
|
706
|
+
upgradeCommand: update.upgradeCommand,
|
|
707
|
+
url: update.url,
|
|
708
|
+
...caveat ? { note: caveat } : {}
|
|
709
|
+
}
|
|
710
|
+
})}
|
|
711
|
+
`;
|
|
712
|
+
}
|
|
713
|
+
if (opts.interactive) {
|
|
714
|
+
return `
|
|
715
|
+
\u2192 canonry ${update.latest} is available (you have ${update.current}).
|
|
716
|
+
Upgrade: ${update.upgradeCommand}
|
|
717
|
+
` + (caveat ? ` ${caveat}
|
|
718
|
+
` : "") + "\n";
|
|
719
|
+
}
|
|
720
|
+
const upgrade = update.installMethod === "docker" ? `Upgrade: ${update.upgradeCommand}.` : `Upgrade with \`${update.upgradeCommand}\`, then restart any running \`canonry serve\`.`;
|
|
721
|
+
return `[canonry] ${UPDATE_AVAILABLE_NOTICE_CODE}: canonry ${update.latest} is available (installed ${update.current}). ${upgrade} ${caveat ? `${caveat} ` : ""}Silence with CANONRY_DISABLE_UPDATE_CHECK=1.
|
|
722
|
+
`;
|
|
723
|
+
}
|
|
677
724
|
var memoryCache = null;
|
|
678
725
|
var inFlight = null;
|
|
679
726
|
function startBackgroundRefresh(getNow) {
|
|
@@ -700,6 +747,22 @@ function checkLatestVersionForServer(opts) {
|
|
|
700
747
|
if (!memoryCache || !memoryCache.latest) return null;
|
|
701
748
|
return buildUpdateAvailable(PKG_VERSION, memoryCache.latest);
|
|
702
749
|
}
|
|
750
|
+
function getServerUpdateStatus(opts) {
|
|
751
|
+
const installMethod = currentInstallMethod();
|
|
752
|
+
const base = { current: PKG_VERSION, installMethod, upgradeCommand: upgradeCommandFor(installMethod), url: NPM_PACKAGE_URL };
|
|
753
|
+
const disabledBy = updateCheckDisabledReason();
|
|
754
|
+
if (disabledBy) return { ...base, enabled: false, disabledBy, latest: null };
|
|
755
|
+
checkLatestVersionForServer(opts);
|
|
756
|
+
let latest = memoryCache?.latest ?? null;
|
|
757
|
+
if (!latest && configExists()) {
|
|
758
|
+
try {
|
|
759
|
+
const cached = loadConfigRaw()?.lastKnownLatestVersion;
|
|
760
|
+
if (typeof cached === "string") latest = cached;
|
|
761
|
+
} catch {
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return { ...base, enabled: true, latest: latest && isStrictSemver(latest) ? latest : null };
|
|
765
|
+
}
|
|
703
766
|
|
|
704
767
|
// src/google-marketing-runtime.ts
|
|
705
768
|
import crypto3 from "crypto";
|
|
@@ -3470,9 +3533,9 @@ function createGoogleMarketingRuntime(options) {
|
|
|
3470
3533
|
// src/server.ts
|
|
3471
3534
|
import { createRequire as createRequire4 } from "module";
|
|
3472
3535
|
import crypto27 from "crypto";
|
|
3473
|
-
import
|
|
3536
|
+
import fs8 from "fs";
|
|
3474
3537
|
import path8 from "path";
|
|
3475
|
-
import { fileURLToPath as
|
|
3538
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3476
3539
|
import { and as and20, eq as eq26 } from "drizzle-orm";
|
|
3477
3540
|
import Fastify from "fastify";
|
|
3478
3541
|
import os4 from "os";
|
|
@@ -5393,12 +5456,12 @@ function sleep2(ms) {
|
|
|
5393
5456
|
}
|
|
5394
5457
|
|
|
5395
5458
|
// ../provider-cdp/src/screenshot.ts
|
|
5396
|
-
import
|
|
5459
|
+
import fs2 from "fs";
|
|
5397
5460
|
import path from "path";
|
|
5398
5461
|
async function captureElementScreenshot(client, selector, outputPath) {
|
|
5399
5462
|
const dir = path.dirname(outputPath);
|
|
5400
|
-
if (!
|
|
5401
|
-
|
|
5463
|
+
if (!fs2.existsSync(dir)) {
|
|
5464
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
5402
5465
|
}
|
|
5403
5466
|
let clip;
|
|
5404
5467
|
try {
|
|
@@ -5432,7 +5495,7 @@ async function captureElementScreenshot(client, selector, outputPath) {
|
|
|
5432
5495
|
}
|
|
5433
5496
|
const { data } = await client.Page.captureScreenshot(screenshotParams);
|
|
5434
5497
|
const buffer = Buffer.from(data, "base64");
|
|
5435
|
-
|
|
5498
|
+
fs2.writeFileSync(outputPath, buffer);
|
|
5436
5499
|
return outputPath;
|
|
5437
5500
|
}
|
|
5438
5501
|
|
|
@@ -6393,7 +6456,7 @@ function nonBlank(value) {
|
|
|
6393
6456
|
return trimmed ? trimmed : void 0;
|
|
6394
6457
|
}
|
|
6395
6458
|
function resolveBuildCommit(env = process.env) {
|
|
6396
|
-
const embedded = true ? "
|
|
6459
|
+
const embedded = true ? "56f0f163c861a247687db8c2087c41218f8ee982" : void 0;
|
|
6397
6460
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
6398
6461
|
}
|
|
6399
6462
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -6405,7 +6468,7 @@ function resolveInstanceIdentity(env = process.env) {
|
|
|
6405
6468
|
|
|
6406
6469
|
// src/job-runner.ts
|
|
6407
6470
|
import crypto6 from "crypto";
|
|
6408
|
-
import
|
|
6471
|
+
import fs3 from "fs";
|
|
6409
6472
|
import path3 from "path";
|
|
6410
6473
|
import os3 from "os";
|
|
6411
6474
|
import { and as and2, eq as eq2, inArray, ne, sql as sql2 } from "drizzle-orm";
|
|
@@ -6973,12 +7036,12 @@ var JobRunner = class {
|
|
|
6973
7036
|
allBrandNames
|
|
6974
7037
|
);
|
|
6975
7038
|
let screenshotRelPath = null;
|
|
6976
|
-
if (raw.screenshotPath &&
|
|
7039
|
+
if (raw.screenshotPath && fs3.existsSync(raw.screenshotPath)) {
|
|
6977
7040
|
const snapshotId = crypto6.randomUUID();
|
|
6978
7041
|
const screenshotDir = path3.join(os3.homedir(), ".canonry", "screenshots", runId);
|
|
6979
|
-
if (!
|
|
7042
|
+
if (!fs3.existsSync(screenshotDir)) fs3.mkdirSync(screenshotDir, { recursive: true });
|
|
6980
7043
|
const destPath = path3.join(screenshotDir, `${snapshotId}.png`);
|
|
6981
|
-
|
|
7044
|
+
fs3.renameSync(raw.screenshotPath, destPath);
|
|
6982
7045
|
screenshotRelPath = `${runId}/${snapshotId}.png`;
|
|
6983
7046
|
this.db.insert(querySnapshots).values({
|
|
6984
7047
|
id: snapshotId,
|
|
@@ -7131,11 +7194,11 @@ var JobRunner = class {
|
|
|
7131
7194
|
);
|
|
7132
7195
|
const snapshotId = crypto6.randomUUID();
|
|
7133
7196
|
let screenshotRelPath = null;
|
|
7134
|
-
if (raw.screenshotPath &&
|
|
7197
|
+
if (raw.screenshotPath && fs3.existsSync(raw.screenshotPath)) {
|
|
7135
7198
|
const screenshotDir = path3.join(os3.homedir(), ".canonry", "screenshots", runId);
|
|
7136
|
-
if (!
|
|
7199
|
+
if (!fs3.existsSync(screenshotDir)) fs3.mkdirSync(screenshotDir, { recursive: true });
|
|
7137
7200
|
const destPath = path3.join(screenshotDir, `${snapshotId}.png`);
|
|
7138
|
-
|
|
7201
|
+
fs3.renameSync(raw.screenshotPath, destPath);
|
|
7139
7202
|
screenshotRelPath = `${runId}/${snapshotId}.png`;
|
|
7140
7203
|
}
|
|
7141
7204
|
this.db.insert(querySnapshots).values({
|
|
@@ -9695,7 +9758,7 @@ function computeSummary(rows) {
|
|
|
9695
9758
|
|
|
9696
9759
|
// src/backlink-extract.ts
|
|
9697
9760
|
import crypto16 from "crypto";
|
|
9698
|
-
import
|
|
9761
|
+
import fs4 from "fs";
|
|
9699
9762
|
import { and as and9, desc as desc5, eq as eq11 } from "drizzle-orm";
|
|
9700
9763
|
var log11 = createLogger("BacklinkExtract");
|
|
9701
9764
|
function defaultDeps3() {
|
|
@@ -9724,7 +9787,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
9724
9787
|
if (!sync.vertexPath || !sync.edgesPath) {
|
|
9725
9788
|
throw new Error(`Release ${sync.release} is missing cached file paths`);
|
|
9726
9789
|
}
|
|
9727
|
-
if (!
|
|
9790
|
+
if (!fs4.existsSync(sync.vertexPath) || !fs4.existsSync(sync.edgesPath)) {
|
|
9728
9791
|
throw new Error(
|
|
9729
9792
|
`Cache for release ${sync.release} is missing from disk (expected at ${sync.vertexPath}). The sync record exists in the database, but the ~16 GB dump was deleted or never present on this machine. Re-sync this release from the Backlinks admin page to restore the cache.`
|
|
9730
9793
|
);
|
|
@@ -12319,7 +12382,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
12319
12382
|
return result;
|
|
12320
12383
|
}
|
|
12321
12384
|
async function backfillInsightsCommand(project, opts) {
|
|
12322
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
12385
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-25NQCETC.js");
|
|
12323
12386
|
const config = loadConfig();
|
|
12324
12387
|
const db = createClient(config.database);
|
|
12325
12388
|
migrate(db);
|
|
@@ -14054,7 +14117,7 @@ import crypto25 from "crypto";
|
|
|
14054
14117
|
import { eq as eq21 } from "drizzle-orm";
|
|
14055
14118
|
|
|
14056
14119
|
// src/agent/session.ts
|
|
14057
|
-
import
|
|
14120
|
+
import fs7 from "fs";
|
|
14058
14121
|
import path7 from "path";
|
|
14059
14122
|
import { Agent } from "@mariozechner/pi-agent-core";
|
|
14060
14123
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
@@ -14298,25 +14361,25 @@ function buildAgentProvidersResponse(config) {
|
|
|
14298
14361
|
}
|
|
14299
14362
|
|
|
14300
14363
|
// src/agent/skill-paths.ts
|
|
14301
|
-
import
|
|
14364
|
+
import fs5 from "fs";
|
|
14302
14365
|
import path5 from "path";
|
|
14303
|
-
import { fileURLToPath } from "url";
|
|
14366
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14304
14367
|
function resolveAeroSkillDir(pkgDir) {
|
|
14305
|
-
const here = pkgDir ?? path5.dirname(
|
|
14368
|
+
const here = pkgDir ?? path5.dirname(fileURLToPath2(import.meta.url));
|
|
14306
14369
|
const candidates = [
|
|
14307
14370
|
path5.join(here, "../assets/agent-workspace/skills/aero"),
|
|
14308
14371
|
path5.join(here, "../../assets/agent-workspace/skills/aero"),
|
|
14309
14372
|
path5.join(here, "../../../../skills/aero")
|
|
14310
14373
|
];
|
|
14311
14374
|
for (const candidate of candidates) {
|
|
14312
|
-
if (
|
|
14375
|
+
if (fs5.existsSync(path5.join(candidate, "SKILL.md"))) return candidate;
|
|
14313
14376
|
}
|
|
14314
14377
|
throw new Error(`Aero skill not found. Searched:
|
|
14315
14378
|
${candidates.join("\n ")}`);
|
|
14316
14379
|
}
|
|
14317
14380
|
|
|
14318
14381
|
// src/agent/skill-tools.ts
|
|
14319
|
-
import
|
|
14382
|
+
import fs6 from "fs";
|
|
14320
14383
|
import path6 from "path";
|
|
14321
14384
|
import { Type } from "@sinclair/typebox";
|
|
14322
14385
|
var MAX_DOC_CHARS = 2e4;
|
|
@@ -14339,12 +14402,12 @@ function parseDescription(body) {
|
|
|
14339
14402
|
}
|
|
14340
14403
|
function scanSkillDocs(skillDir) {
|
|
14341
14404
|
const refsDir = path6.join(skillDir ?? resolveAeroSkillDir(), "references");
|
|
14342
|
-
if (!
|
|
14405
|
+
if (!fs6.existsSync(refsDir)) return [];
|
|
14343
14406
|
const entries = [];
|
|
14344
|
-
for (const file of
|
|
14407
|
+
for (const file of fs6.readdirSync(refsDir)) {
|
|
14345
14408
|
if (!file.endsWith(".md")) continue;
|
|
14346
14409
|
const filePath = path6.join(refsDir, file);
|
|
14347
|
-
const body =
|
|
14410
|
+
const body = fs6.readFileSync(filePath, "utf-8");
|
|
14348
14411
|
entries.push({
|
|
14349
14412
|
slug: file.replace(/\.md$/, ""),
|
|
14350
14413
|
description: parseDescription(body),
|
|
@@ -14388,7 +14451,7 @@ function buildReadSkillDocTool() {
|
|
|
14388
14451
|
});
|
|
14389
14452
|
}
|
|
14390
14453
|
const filePath = path6.join(skillDir, "references", `${match.slug}.md`);
|
|
14391
|
-
const content =
|
|
14454
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
14392
14455
|
if (content.length > MAX_DOC_CHARS) {
|
|
14393
14456
|
return textResult({
|
|
14394
14457
|
slug: match.slug,
|
|
@@ -15049,9 +15112,9 @@ function ensureBuiltinsRegistered() {
|
|
|
15049
15112
|
}
|
|
15050
15113
|
function loadAeroSystemPrompt(pkgDir) {
|
|
15051
15114
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
15052
|
-
const skillBody =
|
|
15115
|
+
const skillBody = fs7.readFileSync(path7.join(skillDir, "SKILL.md"), "utf-8");
|
|
15053
15116
|
const soulPath = path7.join(skillDir, "soul.md");
|
|
15054
|
-
const base =
|
|
15117
|
+
const base = fs7.existsSync(soulPath) ? `${fs7.readFileSync(soulPath, "utf-8").trimEnd()}
|
|
15055
15118
|
|
|
15056
15119
|
---
|
|
15057
15120
|
|
|
@@ -15064,7 +15127,7 @@ function appendSystemPromptExtras(base, env = process.env) {
|
|
|
15064
15127
|
const filePath = env.AERO_SYSTEM_PROMPT_FILE?.trim();
|
|
15065
15128
|
if (filePath) {
|
|
15066
15129
|
try {
|
|
15067
|
-
fileBody =
|
|
15130
|
+
fileBody = fs7.readFileSync(filePath, "utf-8").trim();
|
|
15068
15131
|
} catch {
|
|
15069
15132
|
fileBody = "";
|
|
15070
15133
|
}
|
|
@@ -15551,9 +15614,13 @@ var SessionRegistry = class {
|
|
|
15551
15614
|
if (cached) return cached;
|
|
15552
15615
|
const projectId = this.resolveProjectId(projectName);
|
|
15553
15616
|
const row = this.loadRow(projectId);
|
|
15617
|
+
const systemPrompt = loadAeroSystemPrompt();
|
|
15554
15618
|
if (row) {
|
|
15555
15619
|
const persistedMessages = parseJsonColumn(row.messages, []);
|
|
15556
15620
|
const queued = parseJsonColumn(row.followUpQueue, []);
|
|
15621
|
+
if (row.systemPrompt !== systemPrompt) {
|
|
15622
|
+
this.persistPromptSnapshot(projectId, systemPrompt);
|
|
15623
|
+
}
|
|
15557
15624
|
const effectiveProvider = preferences?.provider ?? row.modelProvider;
|
|
15558
15625
|
const effectiveModelId = preferences?.modelId ?? row.modelId;
|
|
15559
15626
|
if (preferences?.provider || preferences?.modelId) {
|
|
@@ -15569,7 +15636,7 @@ var SessionRegistry = class {
|
|
|
15569
15636
|
config: this.opts.config,
|
|
15570
15637
|
provider: effectiveProvider,
|
|
15571
15638
|
modelId: effectiveModelId,
|
|
15572
|
-
systemPromptOverride: this.buildHydratedSystemPrompt(projectId,
|
|
15639
|
+
systemPromptOverride: this.buildHydratedSystemPrompt(projectId, systemPrompt),
|
|
15573
15640
|
initialMessages: persistedMessages,
|
|
15574
15641
|
toolScope: preferences?.toolScope,
|
|
15575
15642
|
toolProfile: preferences?.toolProfile,
|
|
@@ -15589,7 +15656,6 @@ var SessionRegistry = class {
|
|
|
15589
15656
|
return agent2;
|
|
15590
15657
|
}
|
|
15591
15658
|
const { provider, modelId } = resolveSessionProviderAndModel(this.opts.config, preferences);
|
|
15592
|
-
const systemPrompt = loadAeroSystemPrompt();
|
|
15593
15659
|
const sessionId = crypto25.randomUUID();
|
|
15594
15660
|
const agent = createAeroSession({
|
|
15595
15661
|
projectName,
|
|
@@ -15612,7 +15678,7 @@ var SessionRegistry = class {
|
|
|
15612
15678
|
this.insertRow({
|
|
15613
15679
|
id: sessionId,
|
|
15614
15680
|
projectId,
|
|
15615
|
-
// Persist the raw (unhydrated) prompt
|
|
15681
|
+
// Persist the raw (unhydrated) installed prompt snapshot —
|
|
15616
15682
|
// the `<memory>` block is rebuilt from the notes table on every load.
|
|
15617
15683
|
systemPrompt,
|
|
15618
15684
|
modelProvider: provider,
|
|
@@ -15702,6 +15768,13 @@ ${lines.join("\n")}
|
|
|
15702
15768
|
if (agent.state.isStreaming) {
|
|
15703
15769
|
throw agentBusy(projectName);
|
|
15704
15770
|
}
|
|
15771
|
+
const projectId = this.resolveProjectId(projectName);
|
|
15772
|
+
const row = this.loadRow(projectId);
|
|
15773
|
+
const systemPrompt = loadAeroSystemPrompt();
|
|
15774
|
+
if (row && row.systemPrompt !== systemPrompt) {
|
|
15775
|
+
this.persistPromptSnapshot(projectId, systemPrompt);
|
|
15776
|
+
agent.state.systemPrompt = this.buildHydratedSystemPrompt(projectId, systemPrompt);
|
|
15777
|
+
}
|
|
15705
15778
|
this.alignToolSurface(projectName, agent, {
|
|
15706
15779
|
scope: preferences?.toolScope ?? AeroToolScopes.all,
|
|
15707
15780
|
profile: preferences?.toolProfile ?? AeroToolProfiles.default
|
|
@@ -15984,6 +16057,15 @@ ${lines.join("\n")}
|
|
|
15984
16057
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15985
16058
|
this.opts.db.update(agentSessions).set({ ...patch, updatedAt: now }).where(eq21(agentSessions.projectId, projectId)).run();
|
|
15986
16059
|
}
|
|
16060
|
+
/**
|
|
16061
|
+
* Store a refreshed prompt snapshot without touching `updatedAt`, which the
|
|
16062
|
+
* transcript API reports as the conversation's last activity. Adopting a new
|
|
16063
|
+
* bundled skill is not activity, so it must not make every session look
|
|
16064
|
+
* recently used right after an upgrade.
|
|
16065
|
+
*/
|
|
16066
|
+
persistPromptSnapshot(projectId, systemPrompt) {
|
|
16067
|
+
this.opts.db.update(agentSessions).set({ systemPrompt }).where(eq21(agentSessions.projectId, projectId)).run();
|
|
16068
|
+
}
|
|
15987
16069
|
};
|
|
15988
16070
|
|
|
15989
16071
|
// src/mcp-http.ts
|
|
@@ -16088,7 +16170,8 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
16088
16170
|
credentialScopes: scopes,
|
|
16089
16171
|
operator: request.operatorAccess === true,
|
|
16090
16172
|
tiers: segment.tiers,
|
|
16091
|
-
clientFactory: () => client
|
|
16173
|
+
clientFactory: () => client,
|
|
16174
|
+
updateAvailable: opts.getUpdateAvailable
|
|
16092
16175
|
});
|
|
16093
16176
|
} catch (error) {
|
|
16094
16177
|
if (sessionKey) revokeSessionKey(opts.db, sessionKey.id);
|
|
@@ -18141,7 +18224,7 @@ async function createServer(opts) {
|
|
|
18141
18224
|
});
|
|
18142
18225
|
};
|
|
18143
18226
|
const orphanedOpenClawDir = path8.join(os4.homedir(), ".openclaw-aero");
|
|
18144
|
-
if (
|
|
18227
|
+
if (fs8.existsSync(orphanedOpenClawDir)) {
|
|
18145
18228
|
app.log.warn(
|
|
18146
18229
|
{ path: orphanedOpenClawDir },
|
|
18147
18230
|
"OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
|
|
@@ -19051,7 +19134,7 @@ async function createServer(opts) {
|
|
|
19051
19134
|
const configPath = getConfigPath();
|
|
19052
19135
|
return {
|
|
19053
19136
|
databasePath: opts.config.database,
|
|
19054
|
-
configPath:
|
|
19137
|
+
configPath: fs8.existsSync(configPath) ? configPath : null
|
|
19055
19138
|
};
|
|
19056
19139
|
})(),
|
|
19057
19140
|
// Snapshot the bundled skill trees (version + file hashes) so the
|
|
@@ -19066,6 +19149,8 @@ async function createServer(opts) {
|
|
|
19066
19149
|
}
|
|
19067
19150
|
})(),
|
|
19068
19151
|
getAgentPluginState: opts.getAgentPluginState,
|
|
19152
|
+
// Powers the `canonry.version.current` doctor check. Non-blocking.
|
|
19153
|
+
getUpdateStatus: () => getServerUpdateStatus(),
|
|
19069
19154
|
// Local canonry serve runs on the operator's machine, where pointing a
|
|
19070
19155
|
// webhook at localhost (Discord test container, Pipedream-mock dev server,
|
|
19071
19156
|
// etc.) is a legitimate workflow. Default to allowing it for the local
|
|
@@ -19084,7 +19169,13 @@ async function createServer(opts) {
|
|
|
19084
19169
|
credentials: credentialChecker,
|
|
19085
19170
|
oauthResourceUrl: publicOrigin ? `${publicOrigin}${`${basePath ?? "/"}api/v1/mcp`.replace("//", "/")}` : void 0,
|
|
19086
19171
|
registerAuthenticatedRoutes: async (scope) => {
|
|
19087
|
-
registerMcpHttpRoutes(scope, {
|
|
19172
|
+
registerMcpHttpRoutes(scope, {
|
|
19173
|
+
selfApiUrl: opts.config.apiUrl,
|
|
19174
|
+
issuer: publicOrigin,
|
|
19175
|
+
db: opts.db,
|
|
19176
|
+
// Same non-blocking cache as /health, so hosted agents see the notice too.
|
|
19177
|
+
getUpdateAvailable: () => checkLatestVersionForServer()
|
|
19178
|
+
});
|
|
19088
19179
|
registerOAuthAdminRoutes(scope, { db: opts.db });
|
|
19089
19180
|
if (!sessionRegistry) return;
|
|
19090
19181
|
registerAgentRoutes(scope, { db: opts.db, sessionRegistry });
|
|
@@ -19627,9 +19718,9 @@ async function createServer(opts) {
|
|
|
19627
19718
|
return snapshotService.createReport(input);
|
|
19628
19719
|
}
|
|
19629
19720
|
});
|
|
19630
|
-
const dirname = path8.dirname(
|
|
19721
|
+
const dirname = path8.dirname(fileURLToPath3(import.meta.url));
|
|
19631
19722
|
const assetsDir = opts.assetsDir ?? path8.join(dirname, "..", "assets");
|
|
19632
|
-
if (
|
|
19723
|
+
if (fs8.existsSync(assetsDir)) {
|
|
19633
19724
|
const indexPath = path8.join(assetsDir, "index.html");
|
|
19634
19725
|
const injectConfig = (html, projectTabsOverride, themeOverride, renderTokenOverride) => {
|
|
19635
19726
|
const clientConfig = {};
|
|
@@ -19703,8 +19794,8 @@ async function createServer(opts) {
|
|
|
19703
19794
|
}
|
|
19704
19795
|
});
|
|
19705
19796
|
const serveIndex = (_request, reply) => {
|
|
19706
|
-
if (
|
|
19707
|
-
const html =
|
|
19797
|
+
if (fs8.existsSync(indexPath)) {
|
|
19798
|
+
const html = fs8.readFileSync(indexPath, "utf-8");
|
|
19708
19799
|
return sendSpaDocument(reply, html);
|
|
19709
19800
|
}
|
|
19710
19801
|
return reply.status(404).send({ error: "Dashboard not built" });
|
|
@@ -19735,8 +19826,8 @@ async function createServer(opts) {
|
|
|
19735
19826
|
if (basePath && !url.startsWith(basePath)) {
|
|
19736
19827
|
return reply.status(404).send({ error: "Not found", path: request.url });
|
|
19737
19828
|
}
|
|
19738
|
-
if (
|
|
19739
|
-
const html =
|
|
19829
|
+
if (fs8.existsSync(indexPath)) {
|
|
19830
|
+
const html = fs8.readFileSync(indexPath, "utf-8");
|
|
19740
19831
|
return sendSpaDocument(reply, html);
|
|
19741
19832
|
}
|
|
19742
19833
|
return reply.status(404).send({ error: "Not found" });
|
|
@@ -19900,6 +19991,8 @@ export {
|
|
|
19900
19991
|
setGoogleAuthConfig,
|
|
19901
19992
|
formatAuditFactorScore,
|
|
19902
19993
|
checkLatestVersionForCli,
|
|
19994
|
+
readCachedUpdateAvailable,
|
|
19995
|
+
formatUpdateNotice,
|
|
19903
19996
|
listAgentProviders,
|
|
19904
19997
|
coerceAgentProvider,
|
|
19905
19998
|
AERO_TOOL_PROFILES,
|