@agentyx/core 0.6.0 → 0.7.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/dist/index.d.mts +130 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +342 -51
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { access, readFile, readdir, realpath } from "node:fs/promises";
|
|
3
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
3
|
+
import { delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { constants, readFileSync } from "node:fs";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
//#region src/errors.ts
|
|
@@ -130,13 +130,15 @@ const MCP_CONTEXT_COSTS = [
|
|
|
130
130
|
"high"
|
|
131
131
|
];
|
|
132
132
|
const mcpContextCostSchema = z.enum(MCP_CONTEXT_COSTS);
|
|
133
|
+
const mcpRuntimeSchema = z.enum(["local", "may-download"]);
|
|
133
134
|
const mcpServerNameSchema = z.string().min(1, "MCP server names must be non-empty strings.").regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "MCP server names must be lowercase kebab-case, for example \"context7\".");
|
|
134
135
|
const mcpEnvReferenceSchema = z.strictObject({ fromEnv: z.string().trim().min(1, "Environment variable references must be non-empty strings.").regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "Environment variable names must be valid shell names.") });
|
|
135
136
|
const commonMcpServerDefinitionSchema = z.strictObject({
|
|
136
137
|
name: mcpServerNameSchema.describe("Unique MCP server identifier."),
|
|
137
138
|
description: z.string().trim().min(1, "MCP server descriptions must be non-empty strings."),
|
|
138
139
|
transport: z.enum(["stdio", "http"]),
|
|
139
|
-
contextCost: mcpContextCostSchema.describe("Qualitative context/tool-schema overhead classification; not token accounting.").optional()
|
|
140
|
+
contextCost: mcpContextCostSchema.describe("Qualitative context/tool-schema overhead classification; not token accounting.").optional(),
|
|
141
|
+
runtime: mcpRuntimeSchema.describe("Whether launching this server can fetch a package on first use; see MCP_RUNTIMES.").optional()
|
|
140
142
|
});
|
|
141
143
|
const explicitMcpServerReferenceSchema = z.strictObject({
|
|
142
144
|
name: mcpServerNameSchema.describe("MCP server identifier."),
|
|
@@ -1116,6 +1118,7 @@ const builtInHookRegistry = createHookRegistry([{
|
|
|
1116
1118
|
event: "SessionStart",
|
|
1117
1119
|
command: "npx",
|
|
1118
1120
|
args: [
|
|
1121
|
+
"--no-install",
|
|
1119
1122
|
"agentyx",
|
|
1120
1123
|
"doctor",
|
|
1121
1124
|
"--hook"
|
|
@@ -1245,7 +1248,8 @@ function createMcpServerRegistry(sources) {
|
|
|
1245
1248
|
name: server.name,
|
|
1246
1249
|
description: server.description,
|
|
1247
1250
|
transport: server.transport,
|
|
1248
|
-
contextCost: server.contextCost
|
|
1251
|
+
contextCost: server.contextCost,
|
|
1252
|
+
runtime: server.runtime
|
|
1249
1253
|
};
|
|
1250
1254
|
}),
|
|
1251
1255
|
get
|
|
@@ -1259,6 +1263,7 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1259
1263
|
description: "Fetch up-to-date library documentation from Context7.",
|
|
1260
1264
|
transport: "http",
|
|
1261
1265
|
contextCost: "medium",
|
|
1266
|
+
runtime: "local",
|
|
1262
1267
|
url: "https://mcp.context7.com/mcp"
|
|
1263
1268
|
})
|
|
1264
1269
|
},
|
|
@@ -1269,8 +1274,9 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1269
1274
|
description: "Automate and inspect browsers through Playwright MCP.",
|
|
1270
1275
|
transport: "stdio",
|
|
1271
1276
|
contextCost: "high",
|
|
1277
|
+
runtime: "may-download",
|
|
1272
1278
|
command: "npx",
|
|
1273
|
-
args: ["@playwright/mcp@
|
|
1279
|
+
args: ["@playwright/mcp@0.0.81"]
|
|
1274
1280
|
})
|
|
1275
1281
|
},
|
|
1276
1282
|
{
|
|
@@ -1280,6 +1286,7 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1280
1286
|
description: "Structural code-intelligence MCP backed by a persistent code knowledge graph.",
|
|
1281
1287
|
transport: "stdio",
|
|
1282
1288
|
contextCost: "high",
|
|
1289
|
+
runtime: "local",
|
|
1283
1290
|
command: "codebase-memory-mcp"
|
|
1284
1291
|
})
|
|
1285
1292
|
},
|
|
@@ -1290,6 +1297,7 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1290
1297
|
description: "Read repositories, issues, pull requests and workflow runs on GitHub.",
|
|
1291
1298
|
transport: "http",
|
|
1292
1299
|
contextCost: "high",
|
|
1300
|
+
runtime: "local",
|
|
1293
1301
|
url: "https://api.githubcopilot.com/mcp/"
|
|
1294
1302
|
})
|
|
1295
1303
|
},
|
|
@@ -1300,6 +1308,7 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1300
1308
|
description: "Inspect production issues, events and stack traces recorded by Sentry.",
|
|
1301
1309
|
transport: "http",
|
|
1302
1310
|
contextCost: "medium",
|
|
1311
|
+
runtime: "local",
|
|
1303
1312
|
url: "https://mcp.sentry.dev/mcp"
|
|
1304
1313
|
})
|
|
1305
1314
|
},
|
|
@@ -1310,8 +1319,9 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1310
1319
|
description: "Record performance traces and inspect pages through Chrome DevTools.",
|
|
1311
1320
|
transport: "stdio",
|
|
1312
1321
|
contextCost: "high",
|
|
1322
|
+
runtime: "may-download",
|
|
1313
1323
|
command: "npx",
|
|
1314
|
-
args: ["-y", "chrome-devtools-mcp@
|
|
1324
|
+
args: ["-y", "chrome-devtools-mcp@1.9.0"]
|
|
1315
1325
|
})
|
|
1316
1326
|
},
|
|
1317
1327
|
{
|
|
@@ -1321,8 +1331,9 @@ const builtInMcpServerRegistry = createMcpServerRegistry([
|
|
|
1321
1331
|
description: "Inspect and query Supabase project schemas, tables and logs.",
|
|
1322
1332
|
transport: "stdio",
|
|
1323
1333
|
contextCost: "high",
|
|
1334
|
+
runtime: "may-download",
|
|
1324
1335
|
command: "npx",
|
|
1325
|
-
args: ["-y", "@supabase/mcp-server-supabase@
|
|
1336
|
+
args: ["-y", "@supabase/mcp-server-supabase@0.13.0"],
|
|
1326
1337
|
env: { SUPABASE_ACCESS_TOKEN: { fromEnv: "SUPABASE_ACCESS_TOKEN" } }
|
|
1327
1338
|
})
|
|
1328
1339
|
}
|
|
@@ -1740,13 +1751,92 @@ function getCoreStatus() {
|
|
|
1740
1751
|
return "ready";
|
|
1741
1752
|
}
|
|
1742
1753
|
//#endregion
|
|
1743
|
-
//#region src/project/
|
|
1754
|
+
//#region src/project/executable.ts
|
|
1755
|
+
/** Whether `command` resolves to an executable file, via `PATH` unless it already contains a `/`. */
|
|
1756
|
+
async function isExecutableOnPath(command) {
|
|
1757
|
+
if (command.includes("/")) return isFileExecutable(command);
|
|
1758
|
+
for (const directory of (process.env.PATH ?? "").split(delimiter)) {
|
|
1759
|
+
if (directory.length === 0) continue;
|
|
1760
|
+
if (await isFileExecutable(`${directory}/${command}`)) return true;
|
|
1761
|
+
}
|
|
1762
|
+
return false;
|
|
1763
|
+
}
|
|
1764
|
+
async function isFileExecutable(path) {
|
|
1765
|
+
try {
|
|
1766
|
+
await access(path, constants.X_OK);
|
|
1767
|
+
return true;
|
|
1768
|
+
} catch {
|
|
1769
|
+
return false;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
//#endregion
|
|
1773
|
+
//#region src/project/signals.ts
|
|
1744
1774
|
const PACKAGE_MANAGERS = [
|
|
1745
1775
|
"pnpm",
|
|
1746
1776
|
"npm",
|
|
1747
1777
|
"yarn",
|
|
1748
1778
|
"bun"
|
|
1749
1779
|
];
|
|
1780
|
+
/** Package name patterns matched exactly, or as a `@scope/*` prefix. */
|
|
1781
|
+
const TEST_FRAMEWORK_PATTERNS = [
|
|
1782
|
+
"vitest",
|
|
1783
|
+
"jest",
|
|
1784
|
+
"@jest/*",
|
|
1785
|
+
"@playwright/test",
|
|
1786
|
+
"cypress",
|
|
1787
|
+
"karma"
|
|
1788
|
+
];
|
|
1789
|
+
const BROWSER_TESTING_PATTERNS = ["@playwright/test", "cypress"];
|
|
1790
|
+
const OBSERVABILITY_PATTERNS = ["@sentry/*", "@opentelemetry/*"];
|
|
1791
|
+
const DATA_TOOLING_PATTERNS = [
|
|
1792
|
+
"@supabase/*",
|
|
1793
|
+
"drizzle-orm",
|
|
1794
|
+
"prisma",
|
|
1795
|
+
"@prisma/client",
|
|
1796
|
+
"typeorm",
|
|
1797
|
+
"sequelize"
|
|
1798
|
+
];
|
|
1799
|
+
const ACCESSIBILITY_PATTERNS = [
|
|
1800
|
+
"axe-core",
|
|
1801
|
+
"@axe-core/*",
|
|
1802
|
+
"pa11y"
|
|
1803
|
+
];
|
|
1804
|
+
const DEPENDENCY_FIELDS = [
|
|
1805
|
+
"dependencies",
|
|
1806
|
+
"devDependencies",
|
|
1807
|
+
"peerDependencies",
|
|
1808
|
+
"optionalDependencies"
|
|
1809
|
+
];
|
|
1810
|
+
const CONTAINER_IGNORED = /* @__PURE__ */ new Set([
|
|
1811
|
+
"node_modules",
|
|
1812
|
+
".git",
|
|
1813
|
+
"dist",
|
|
1814
|
+
"build",
|
|
1815
|
+
"coverage"
|
|
1816
|
+
]);
|
|
1817
|
+
/** Extensions counted as source files by the bounded repository-size scan. */
|
|
1818
|
+
const SOURCE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1819
|
+
".ts",
|
|
1820
|
+
".tsx",
|
|
1821
|
+
".js",
|
|
1822
|
+
".jsx",
|
|
1823
|
+
".mjs",
|
|
1824
|
+
".cjs",
|
|
1825
|
+
".vue",
|
|
1826
|
+
".svelte",
|
|
1827
|
+
".py",
|
|
1828
|
+
".go",
|
|
1829
|
+
".rs",
|
|
1830
|
+
".java",
|
|
1831
|
+
".kt",
|
|
1832
|
+
".rb",
|
|
1833
|
+
".php",
|
|
1834
|
+
".css",
|
|
1835
|
+
".scss",
|
|
1836
|
+
".html"
|
|
1837
|
+
]);
|
|
1838
|
+
/** Maximum directory entries visited by `scanRepositorySize`, regardless of match. */
|
|
1839
|
+
const REPOSITORY_SCAN_ENTRY_LIMIT = 5e3;
|
|
1750
1840
|
const lockfileManagers = /* @__PURE__ */ new Map([
|
|
1751
1841
|
["pnpm-lock.yaml", "pnpm"],
|
|
1752
1842
|
["package-lock.json", "npm"],
|
|
@@ -1754,52 +1844,141 @@ const lockfileManagers = /* @__PURE__ */ new Map([
|
|
|
1754
1844
|
["bun.lock", "bun"],
|
|
1755
1845
|
["bun.lockb", "bun"]
|
|
1756
1846
|
]);
|
|
1757
|
-
|
|
1847
|
+
/** Gathers every project signal with a bounded, cheap set of reads. */
|
|
1848
|
+
async function collectProjectSignals(projectDir) {
|
|
1758
1849
|
const packageJsonPath = join(projectDir, "package.json");
|
|
1759
|
-
const
|
|
1760
|
-
const
|
|
1761
|
-
const
|
|
1850
|
+
const packageJsonResult = await readPackageJson(packageJsonPath);
|
|
1851
|
+
const packageJson = packageJsonResult.data;
|
|
1852
|
+
const [packageManager, containers, ci, monorepo, repositorySize, tsconfig, rtkAvailable] = await Promise.all([
|
|
1853
|
+
detectPackageManager(projectDir, packageJson),
|
|
1854
|
+
detectContainerFiles(projectDir),
|
|
1855
|
+
detectCiFiles(projectDir),
|
|
1856
|
+
detectMonorepo(projectDir, packageJson),
|
|
1857
|
+
scanRepositorySize(projectDir),
|
|
1858
|
+
exists(join(projectDir, "tsconfig.json")),
|
|
1859
|
+
isExecutableOnPath(builtInToolRegistry.get("rtk").command)
|
|
1860
|
+
]);
|
|
1762
1861
|
return {
|
|
1763
1862
|
projectDir,
|
|
1764
1863
|
packageJson: {
|
|
1765
|
-
present:
|
|
1766
|
-
valid:
|
|
1864
|
+
present: packageJsonResult.present,
|
|
1865
|
+
valid: packageJsonResult.valid,
|
|
1767
1866
|
path: packageJsonPath,
|
|
1768
|
-
name: getString(packageJson
|
|
1769
|
-
packageManager: getString(packageJson
|
|
1770
|
-
error:
|
|
1867
|
+
name: getString(packageJson?.name),
|
|
1868
|
+
packageManager: getString(packageJson?.packageManager),
|
|
1869
|
+
error: packageJsonResult.error
|
|
1771
1870
|
},
|
|
1772
1871
|
packageManager,
|
|
1773
|
-
|
|
1774
|
-
|
|
1872
|
+
typescript: {
|
|
1873
|
+
dependency: findDependency(packageJson, "typescript"),
|
|
1874
|
+
tsconfig
|
|
1875
|
+
},
|
|
1876
|
+
angular: findDependency(packageJson, "@angular/core"),
|
|
1877
|
+
testFrameworks: findAnyDependency(packageJson, TEST_FRAMEWORK_PATTERNS),
|
|
1878
|
+
browserTesting: findAnyDependency(packageJson, BROWSER_TESTING_PATTERNS),
|
|
1879
|
+
observability: findAnyDependency(packageJson, OBSERVABILITY_PATTERNS),
|
|
1880
|
+
dataTooling: findAnyDependency(packageJson, DATA_TOOLING_PATTERNS),
|
|
1881
|
+
accessibilityTooling: findAnyDependency(packageJson, ACCESSIBILITY_PATTERNS),
|
|
1882
|
+
containers,
|
|
1883
|
+
ci,
|
|
1884
|
+
monorepo,
|
|
1885
|
+
repositorySize,
|
|
1886
|
+
localTools: { rtkAvailable }
|
|
1775
1887
|
};
|
|
1776
1888
|
}
|
|
1777
|
-
|
|
1889
|
+
/**
|
|
1890
|
+
* Counts source-like files under a bounded traversal, ignoring dependency, VCS and build output
|
|
1891
|
+
* directories. Stops after visiting `entryLimit` directory entries — cheap even on a monorepo — and
|
|
1892
|
+
* reports `capped` so callers never mistake a partial scan for a complete one.
|
|
1893
|
+
*/
|
|
1894
|
+
async function scanRepositorySize(projectDir, options = {}) {
|
|
1895
|
+
const entryLimit = options.entryLimit ?? 5e3;
|
|
1896
|
+
const directories = [projectDir];
|
|
1897
|
+
let filesScanned = 0;
|
|
1898
|
+
let entriesVisited = 0;
|
|
1899
|
+
let capped = false;
|
|
1900
|
+
while (directories.length > 0 && !capped) {
|
|
1901
|
+
const directory = directories.shift();
|
|
1902
|
+
if (directory === void 0) break;
|
|
1903
|
+
let entries;
|
|
1904
|
+
try {
|
|
1905
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
1906
|
+
} catch {
|
|
1907
|
+
continue;
|
|
1908
|
+
}
|
|
1909
|
+
for (const entry of entries) {
|
|
1910
|
+
if (entriesVisited >= entryLimit) {
|
|
1911
|
+
capped = true;
|
|
1912
|
+
break;
|
|
1913
|
+
}
|
|
1914
|
+
entriesVisited += 1;
|
|
1915
|
+
if (entry.isDirectory()) {
|
|
1916
|
+
if (entry.name.startsWith(".") || CONTAINER_IGNORED.has(entry.name)) continue;
|
|
1917
|
+
directories.push(join(directory, entry.name));
|
|
1918
|
+
} else if (entry.isFile() && SOURCE_FILE_EXTENSIONS.has(extname(entry.name))) filesScanned += 1;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1778
1921
|
return {
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
targets: [...input.targets]
|
|
1922
|
+
filesScanned,
|
|
1923
|
+
capped
|
|
1782
1924
|
};
|
|
1783
1925
|
}
|
|
1784
|
-
function
|
|
1785
|
-
|
|
1926
|
+
function findDependency(packageJson, pattern) {
|
|
1927
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
1928
|
+
const value = packageJson?.[field];
|
|
1929
|
+
if (!isRecord(value)) continue;
|
|
1930
|
+
if (pattern.endsWith("/*")) {
|
|
1931
|
+
const prefix = pattern.slice(0, -1);
|
|
1932
|
+
const name = Object.keys(value).find((key) => key.startsWith(prefix));
|
|
1933
|
+
if (name !== void 0) return {
|
|
1934
|
+
dependency: name,
|
|
1935
|
+
field
|
|
1936
|
+
};
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
if (pattern in value) return {
|
|
1940
|
+
dependency: pattern,
|
|
1941
|
+
field
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1786
1944
|
}
|
|
1787
|
-
function
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1945
|
+
function findAnyDependency(packageJson, patterns) {
|
|
1946
|
+
const matches = [];
|
|
1947
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1948
|
+
for (const pattern of patterns) {
|
|
1949
|
+
const match = findDependency(packageJson, pattern);
|
|
1950
|
+
if (match !== void 0 && !seen.has(match.dependency)) {
|
|
1951
|
+
seen.add(match.dependency);
|
|
1952
|
+
matches.push(match);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
return matches;
|
|
1956
|
+
}
|
|
1957
|
+
async function detectContainerFiles(projectDir) {
|
|
1958
|
+
const [dockerfile, dockerCompose, compose] = await Promise.all([
|
|
1959
|
+
exists(join(projectDir, "Dockerfile")),
|
|
1960
|
+
exists(join(projectDir, "docker-compose.yml")),
|
|
1961
|
+
exists(join(projectDir, "compose.yml"))
|
|
1962
|
+
]);
|
|
1963
|
+
return {
|
|
1964
|
+
dockerfile,
|
|
1965
|
+
compose: dockerCompose || compose
|
|
1966
|
+
};
|
|
1795
1967
|
}
|
|
1796
|
-
async function
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
if (
|
|
1802
|
-
|
|
1968
|
+
async function detectCiFiles(projectDir) {
|
|
1969
|
+
return { githubActions: await exists(join(projectDir, ".github", "workflows")) };
|
|
1970
|
+
}
|
|
1971
|
+
async function detectMonorepo(projectDir, packageJson) {
|
|
1972
|
+
const markers = [];
|
|
1973
|
+
if (await exists(join(projectDir, "pnpm-workspace.yaml"))) markers.push("pnpm-workspace.yaml");
|
|
1974
|
+
if (await exists(join(projectDir, "turbo.json"))) markers.push("turbo.json");
|
|
1975
|
+
if (await exists(join(projectDir, "nx.json"))) markers.push("nx.json");
|
|
1976
|
+
const workspaces = packageJson?.workspaces;
|
|
1977
|
+
if (Array.isArray(workspaces) || isRecord(workspaces)) markers.push("package.json workspaces");
|
|
1978
|
+
return {
|
|
1979
|
+
detected: markers.length > 0,
|
|
1980
|
+
markers
|
|
1981
|
+
};
|
|
1803
1982
|
}
|
|
1804
1983
|
async function detectPackageManager(projectDir, packageJson) {
|
|
1805
1984
|
const lockfiles = [];
|
|
@@ -1862,16 +2041,6 @@ async function readPackageJson(path) {
|
|
|
1862
2041
|
};
|
|
1863
2042
|
}
|
|
1864
2043
|
}
|
|
1865
|
-
function collectDependencies(packageJson) {
|
|
1866
|
-
const dependencies = /* @__PURE__ */ new Set();
|
|
1867
|
-
for (const field of [
|
|
1868
|
-
packageJson?.dependencies,
|
|
1869
|
-
packageJson?.devDependencies,
|
|
1870
|
-
packageJson?.peerDependencies,
|
|
1871
|
-
packageJson?.optionalDependencies
|
|
1872
|
-
]) if (isRecord(field)) for (const name of Object.keys(field)) dependencies.add(name);
|
|
1873
|
-
return dependencies;
|
|
1874
|
-
}
|
|
1875
2044
|
function parsePackageManagerName(value) {
|
|
1876
2045
|
const name = value?.split("@")[0];
|
|
1877
2046
|
return PACKAGE_MANAGERS.includes(name) ? name : void 0;
|
|
@@ -1895,6 +2064,128 @@ function isNotFound(cause) {
|
|
|
1895
2064
|
return cause instanceof Error && cause.code === "ENOENT";
|
|
1896
2065
|
}
|
|
1897
2066
|
//#endregion
|
|
2067
|
+
//#region src/project/detector.ts
|
|
2068
|
+
/**
|
|
2069
|
+
* Factual project detection only. It gathers `ProjectSignals` and never decides which packs or
|
|
2070
|
+
* capabilities fit — that policy lives in `recommendCapabilities`, kept separate so each half stays
|
|
2071
|
+
* independently testable.
|
|
2072
|
+
*/
|
|
2073
|
+
async function detectProject(projectDir) {
|
|
2074
|
+
const signals = await collectProjectSignals(projectDir);
|
|
2075
|
+
return {
|
|
2076
|
+
projectDir,
|
|
2077
|
+
packageJson: signals.packageJson,
|
|
2078
|
+
packageManager: signals.packageManager,
|
|
2079
|
+
signals
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
function buildAgentyxConfig(input) {
|
|
2083
|
+
return {
|
|
2084
|
+
packs: [...input.packs],
|
|
2085
|
+
enable: [...input.enable ?? []],
|
|
2086
|
+
targets: [...input.targets]
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
function formatAgentyxConfig(config) {
|
|
2090
|
+
return `${JSON.stringify(config, null, 2)}\n`;
|
|
2091
|
+
}
|
|
2092
|
+
//#endregion
|
|
2093
|
+
//#region src/project/recommend.ts
|
|
2094
|
+
const RECOMMENDATION_CONFIDENCES = ["high", "medium"];
|
|
2095
|
+
/**
|
|
2096
|
+
* Heuristic thresholds for the `codebase-memory` capability suggestion, in scanned source files.
|
|
2097
|
+
* These are approximate signals, not exact token accounting, and a monorepo is treated as already
|
|
2098
|
+
* complex enough to lower the bar.
|
|
2099
|
+
*/
|
|
2100
|
+
const CODEBASE_MEMORY_FILE_THRESHOLD = 2e3;
|
|
2101
|
+
const CODEBASE_MEMORY_MONOREPO_FILE_THRESHOLD = 800;
|
|
2102
|
+
/**
|
|
2103
|
+
* Applies conservative, deterministic policy on top of `ProjectSignals`. This is the only place
|
|
2104
|
+
* that turns an observed fact into a product suggestion — `ProjectSignals` stays fact-only so it
|
|
2105
|
+
* can be tested independently of pack names or capability policy.
|
|
2106
|
+
*
|
|
2107
|
+
* Never enables anything and never touches the filesystem: the caller decides what, if anything,
|
|
2108
|
+
* to do with the result.
|
|
2109
|
+
*/
|
|
2110
|
+
function recommendCapabilities(signals, options = {}) {
|
|
2111
|
+
const packs = recommendPacks(signals);
|
|
2112
|
+
const configuredPacks = options.configuredPacks ?? [];
|
|
2113
|
+
return {
|
|
2114
|
+
packs,
|
|
2115
|
+
capabilities: recommendOptionalCapabilities(signals, /* @__PURE__ */ new Set([...packs.map((pack) => pack.name), ...configuredPacks]), configuredPacks)
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2118
|
+
function recommendPacks(signals) {
|
|
2119
|
+
const packs = [];
|
|
2120
|
+
if (signals.packageJson.present) packs.push(packRecommendation("technical", "high", ["package.json detected — baseline engineering practices apply to any software project."]));
|
|
2121
|
+
const typescriptReasons = [...signals.typescript.dependency !== void 0 ? [dependencyReason("TypeScript", signals.typescript.dependency)] : [], ...signals.typescript.tsconfig ? ["tsconfig.json detected."] : []];
|
|
2122
|
+
if (typescriptReasons.length > 0) packs.push(packRecommendation("typescript", "high", typescriptReasons));
|
|
2123
|
+
if (signals.angular !== void 0) packs.push(packRecommendation("angular", "high", [dependencyReason("@angular/core", signals.angular)]));
|
|
2124
|
+
const testingMatches = dedupeMatches([...signals.testFrameworks, ...signals.browserTesting]);
|
|
2125
|
+
if (testingMatches.length > 0) packs.push(packRecommendation("testing", "high", testingMatches.map((match) => dependencyReason(match.dependency, match))));
|
|
2126
|
+
const devopsReasons = [
|
|
2127
|
+
...signals.containers.dockerfile ? ["Dockerfile detected."] : [],
|
|
2128
|
+
...signals.containers.compose ? ["Container compose file detected."] : [],
|
|
2129
|
+
...signals.ci.githubActions ? ["GitHub Actions workflow detected (.github/workflows)."] : []
|
|
2130
|
+
];
|
|
2131
|
+
if (devopsReasons.length > 0) packs.push(packRecommendation("devops", "high", devopsReasons));
|
|
2132
|
+
if (signals.observability.length > 0) packs.push(packRecommendation("observability", "high", signals.observability.map((match) => dependencyReason(match.dependency, match))));
|
|
2133
|
+
if (signals.dataTooling.length > 0) packs.push(packRecommendation("data", "high", signals.dataTooling.map((match) => dependencyReason(match.dependency, match))));
|
|
2134
|
+
if (signals.accessibilityTooling.length > 0) packs.push(packRecommendation("accessibility", "high", signals.accessibilityTooling.map((match) => dependencyReason(match.dependency, match))));
|
|
2135
|
+
return packs;
|
|
2136
|
+
}
|
|
2137
|
+
function recommendOptionalCapabilities(signals, activePacks, configuredPacks) {
|
|
2138
|
+
const capabilities = [];
|
|
2139
|
+
const playwrightMatch = signals.browserTesting.find((match) => match.dependency === "@playwright/test");
|
|
2140
|
+
if (activePacks.has("testing") && playwrightMatch !== void 0) capabilities.push(capabilityRecommendation("playwright", "high", ["Playwright is already part of this project; browser MCP may be useful for interactive browser work."]));
|
|
2141
|
+
if (signals.observability.find((match) => match.dependency.startsWith("@sentry/")) !== void 0) capabilities.push(capabilityRecommendation("sentry", "high", ["Sentry is already configured as a dependency."]));
|
|
2142
|
+
if (signals.dataTooling.find((match) => match.dependency.startsWith("@supabase/")) !== void 0) capabilities.push(capabilityRecommendation("supabase", "high", ["Supabase is already configured as a dependency."]));
|
|
2143
|
+
if (configuredPacks.includes("efficiency") && signals.localTools.rtkAvailable) capabilities.push(capabilityRecommendation("rtk", "high", ["RTK is already installed locally."]));
|
|
2144
|
+
const sizeThreshold = signals.monorepo.detected ? 800 : CODEBASE_MEMORY_FILE_THRESHOLD;
|
|
2145
|
+
if (signals.repositorySize.filesScanned >= sizeThreshold || signals.repositorySize.capped) capabilities.push(capabilityRecommendation("codebase-memory", "medium", [repositorySizeReason(signals)]));
|
|
2146
|
+
return capabilities;
|
|
2147
|
+
}
|
|
2148
|
+
function repositorySizeReason(signals) {
|
|
2149
|
+
const { filesScanned, capped } = signals.repositorySize;
|
|
2150
|
+
const scope = signals.monorepo.detected ? " across this monorepo" : "";
|
|
2151
|
+
return `Heuristic: found ${capped ? `at least ${filesScanned} source files (the scan was capped before finishing)` : `${filesScanned} source files`}${scope}. A persistent codebase-memory MCP may reduce repeated full-tree reads on a repository this size — this is an approximate signal, not an exact token measurement.`;
|
|
2152
|
+
}
|
|
2153
|
+
function packRecommendation(name, confidence, reasons) {
|
|
2154
|
+
return {
|
|
2155
|
+
kind: "pack",
|
|
2156
|
+
name,
|
|
2157
|
+
confidence,
|
|
2158
|
+
reasons
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
/** Provenance comes from the pack registry itself — never a second, hand-maintained capability map. */
|
|
2162
|
+
function capabilityRecommendation(name, confidence, reasons) {
|
|
2163
|
+
return {
|
|
2164
|
+
kind: "capability",
|
|
2165
|
+
name,
|
|
2166
|
+
confidence,
|
|
2167
|
+
reasons,
|
|
2168
|
+
contributedBy: packsDeclaringOptionalCapability(name)
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
function packsDeclaringOptionalCapability(name) {
|
|
2172
|
+
const packs = [];
|
|
2173
|
+
for (const pack of builtInPackRegistry.values()) if (pack.mcpServers.some((server) => server.name === name && server.activation === "optional") || pack.tools.some((tool) => tool.name === name && tool.activation === "optional") || pack.hooks.some((hook) => hook.name === name && hook.activation === "optional")) packs.push(pack.name);
|
|
2174
|
+
return packs;
|
|
2175
|
+
}
|
|
2176
|
+
function dependencyReason(label, match) {
|
|
2177
|
+
return label === match.dependency ? `Detected ${match.dependency} in ${match.field}.` : `Detected ${label} (${match.dependency}) in ${match.field}.`;
|
|
2178
|
+
}
|
|
2179
|
+
function dedupeMatches(matches) {
|
|
2180
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2181
|
+
const result = [];
|
|
2182
|
+
for (const match of matches) if (!seen.has(match.dependency)) {
|
|
2183
|
+
seen.add(match.dependency);
|
|
2184
|
+
result.push(match);
|
|
2185
|
+
}
|
|
2186
|
+
return result;
|
|
2187
|
+
}
|
|
2188
|
+
//#endregion
|
|
1898
2189
|
//#region src/source/inspection.ts
|
|
1899
2190
|
async function inspectTrustedSource(projectPath, reference) {
|
|
1900
2191
|
const definition = getTrustedSourceDefinition(reference);
|
|
@@ -1983,6 +2274,6 @@ function trustedSourceLoadError(sourceName, reason, cause) {
|
|
|
1983
2274
|
return new TrustedSourceLoadError(sourceName, reason, cause instanceof Error ? { cause } : void 0);
|
|
1984
2275
|
}
|
|
1985
2276
|
//#endregion
|
|
1986
|
-
export { AGENTYX_CONFIG_FILENAME, AGENTYX_CONFIG_SCHEMA_ID, AGENTYX_MANIFEST_FILENAME, AgentyxConfigNotFoundError, AgentyxConfigParseError, AgentyxConfigValidationError, AgentyxError, AgentyxManifestParseError, AgentyxManifestValidationError, CircularPackDependencyError, DuplicateHookError, DuplicateMcpServerError, DuplicatePackError, DuplicateSkillError, DuplicateToolError, DuplicateTrustedSourceError, HOOK_ACTIVATION_LEVELS, HOOK_EVENTS, INSTALL_MANIFEST_VERSION, InvalidHookError, InvalidMcpServerError, InvalidSkillError, InvalidToolError, LocalSkillDirectoryError, MCP_CAPABILITY_LEVELS, MCP_CONTEXT_COSTS, PACKAGE_MANAGERS, PACK_CATEGORIES, TOOL_ACTIVATION_LEVELS, TrustedSourceLoadError, UnknownEnabledCapabilityError, UnknownHookError, UnknownMcpServerError, UnknownPackError, UnknownSkillError, UnknownToolError, UnknownTrustedSourceError, agentyxConfigPath, agentyxConfigSchema, agentyxCoreName, agentyxManifestPath, agentyxTargetSchema, buildAgentyxConfig, buildAgentyxConfigJsonSchema, builtInHookNames, builtInHookRegistry, builtInMcpServerNames, builtInMcpServerRegistry, builtInPackRegistry, builtInPacks, builtInSkillNames, builtInSkillRegistry, builtInToolNames, builtInToolRegistry, codexPluginManifestSchema, collectPackHookReferences, collectPackHooks, collectPackMcpServerReferences, collectPackMcpServers, collectPackToolReferences, createHookRegistry, createMcpServerRegistry, createPackRegistry, createSkillRegistry, createToolRegistry, createTrustedSourceRegistry, detectProject, emptyInstallManifest, enabledCapabilityNameSchema, filterEffectiveHooks, filterEffectiveMcpServers, filterEffectiveTools, formatAgentyxConfig, formatInstallManifest, formatSkillMarkdown, getCoreStatus, getTrustedSourceDefinition, hashContent, hookActivationLevelSchema, hookDefinitionSchema, hookEventSchema, hookManifestEntrySchema, hookNameSchema, hookReferenceSchema, inspectTrustedSource, installManifestEntrySchema, installManifestSchema, knownTrustedSourceRegistry, knownTrustedSources, loadAgentyxConfig, loadAgentyxProject, loadInstallManifest, manifestEntriesByPath, mcpCapabilityLevelSchema, mcpContextCostSchema, mcpEnvReferenceSchema, mcpManifestEntrySchema, mcpServerDefinitionSchema, mcpServerReferenceSchema, packCategorySchema, packDefinitionSchema, packNameSchema, parseAgentyxConfig, parseInstallManifest, parseSkillMarkdown, resolveAgentyxConfig, resolvePackHookReferences, resolvePackHooks, resolvePackMcpServerReferences, resolvePackMcpServers, resolvePackSkills, resolvePackToolReferences, resolvePackTools, resolvePacks, skillDefinitionSchema, skillDirectorySchema, skillManifestEntrySchema, toolActivationLevelSchema, toolDefinitionSchema, toolNameSchema, toolReferenceSchema, trustedSourceDefinitionSchema, trustedSourceNameSchema, trustedSourcePathSchema, trustedSourceReferenceSchema, trustedSourceSkillSummarySchema };
|
|
2277
|
+
export { AGENTYX_CONFIG_FILENAME, AGENTYX_CONFIG_SCHEMA_ID, AGENTYX_MANIFEST_FILENAME, AgentyxConfigNotFoundError, AgentyxConfigParseError, AgentyxConfigValidationError, AgentyxError, AgentyxManifestParseError, AgentyxManifestValidationError, CODEBASE_MEMORY_FILE_THRESHOLD, CODEBASE_MEMORY_MONOREPO_FILE_THRESHOLD, CircularPackDependencyError, DuplicateHookError, DuplicateMcpServerError, DuplicatePackError, DuplicateSkillError, DuplicateToolError, DuplicateTrustedSourceError, HOOK_ACTIVATION_LEVELS, HOOK_EVENTS, INSTALL_MANIFEST_VERSION, InvalidHookError, InvalidMcpServerError, InvalidSkillError, InvalidToolError, LocalSkillDirectoryError, MCP_CAPABILITY_LEVELS, MCP_CONTEXT_COSTS, PACKAGE_MANAGERS, PACK_CATEGORIES, RECOMMENDATION_CONFIDENCES, REPOSITORY_SCAN_ENTRY_LIMIT, TOOL_ACTIVATION_LEVELS, TrustedSourceLoadError, UnknownEnabledCapabilityError, UnknownHookError, UnknownMcpServerError, UnknownPackError, UnknownSkillError, UnknownToolError, UnknownTrustedSourceError, agentyxConfigPath, agentyxConfigSchema, agentyxCoreName, agentyxManifestPath, agentyxTargetSchema, buildAgentyxConfig, buildAgentyxConfigJsonSchema, builtInHookNames, builtInHookRegistry, builtInMcpServerNames, builtInMcpServerRegistry, builtInPackRegistry, builtInPacks, builtInSkillNames, builtInSkillRegistry, builtInToolNames, builtInToolRegistry, codexPluginManifestSchema, collectPackHookReferences, collectPackHooks, collectPackMcpServerReferences, collectPackMcpServers, collectPackToolReferences, collectProjectSignals, createHookRegistry, createMcpServerRegistry, createPackRegistry, createSkillRegistry, createToolRegistry, createTrustedSourceRegistry, detectProject, emptyInstallManifest, enabledCapabilityNameSchema, filterEffectiveHooks, filterEffectiveMcpServers, filterEffectiveTools, formatAgentyxConfig, formatInstallManifest, formatSkillMarkdown, getCoreStatus, getTrustedSourceDefinition, hashContent, hookActivationLevelSchema, hookDefinitionSchema, hookEventSchema, hookManifestEntrySchema, hookNameSchema, hookReferenceSchema, inspectTrustedSource, installManifestEntrySchema, installManifestSchema, isExecutableOnPath, knownTrustedSourceRegistry, knownTrustedSources, loadAgentyxConfig, loadAgentyxProject, loadInstallManifest, manifestEntriesByPath, mcpCapabilityLevelSchema, mcpContextCostSchema, mcpEnvReferenceSchema, mcpManifestEntrySchema, mcpServerDefinitionSchema, mcpServerReferenceSchema, packCategorySchema, packDefinitionSchema, packNameSchema, parseAgentyxConfig, parseInstallManifest, parseSkillMarkdown, recommendCapabilities, resolveAgentyxConfig, resolvePackHookReferences, resolvePackHooks, resolvePackMcpServerReferences, resolvePackMcpServers, resolvePackSkills, resolvePackToolReferences, resolvePackTools, resolvePacks, scanRepositorySize, skillDefinitionSchema, skillDirectorySchema, skillManifestEntrySchema, toolActivationLevelSchema, toolDefinitionSchema, toolNameSchema, toolReferenceSchema, trustedSourceDefinitionSchema, trustedSourceNameSchema, trustedSourcePathSchema, trustedSourceReferenceSchema, trustedSourceSkillSummarySchema };
|
|
1987
2278
|
|
|
1988
2279
|
//# sourceMappingURL=index.mjs.map
|