@agentyx/core 0.4.0 → 0.5.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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- import { access, readFile } from "node:fs/promises";
3
- import { join, resolve } from "node:path";
2
+ import { access, readFile, readdir, realpath } from "node:fs/promises";
3
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { readFileSync } from "node:fs";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { createHash } from "node:crypto";
@@ -87,6 +87,15 @@ var UnknownEnabledCapabilityError = class extends AgentyxError {
87
87
  this.knownCapabilities = knownCapabilities;
88
88
  }
89
89
  };
90
+ /** Raised when a configured local Skill directory cannot be loaded safely. */
91
+ var LocalSkillDirectoryError = class extends AgentyxError {
92
+ directory;
93
+ constructor(directory, reason, options) {
94
+ super("local_skill_directory_error", `Could not load local Skill directory "${directory}": ${reason}`, options);
95
+ this.name = "LocalSkillDirectoryError";
96
+ this.directory = directory;
97
+ }
98
+ };
90
99
  //#endregion
91
100
  //#region src/mcp/schema.ts
92
101
  const MCP_CAPABILITY_LEVELS = ["default", "optional"];
@@ -198,6 +207,39 @@ const packDefinitionSchema = z.strictObject({
198
207
  tools: z.array(toolReferenceSchema).describe("Local tools this pack contributes, in declaration order.").default([])
199
208
  });
200
209
  //#endregion
210
+ //#region src/source/schema.ts
211
+ const trustedSourceNameSchema = z.string().min(1, "Trusted source names must be non-empty strings.").regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Trusted source names must be lowercase kebab-case, for example \"superpowers\".");
212
+ const trustedSourcePathSchema = z.string().min(1, "Trusted source paths must be non-empty strings.").regex(/^(?!\/)(?![A-Za-z]:)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/, "Trusted source paths must be portable project-relative paths without parent traversal.");
213
+ const trustedSourceReferenceSchema = z.strictObject({
214
+ name: trustedSourceNameSchema.describe("Known trusted source identifier."),
215
+ path: trustedSourcePathSchema.describe("Project-relative checkout path for this source."),
216
+ ref: z.string().trim().min(1, "Trusted source refs must be non-empty strings.").describe("Reviewed immutable commit, signed tag or pinned release identifier.")
217
+ });
218
+ const trustedSourceDefinitionSchema = z.strictObject({
219
+ name: trustedSourceNameSchema,
220
+ displayName: z.string().min(1),
221
+ repository: z.string().url(),
222
+ type: z.literal("codex-plugin"),
223
+ manifestPath: z.string().min(1),
224
+ recommendedPath: trustedSourcePathSchema,
225
+ description: z.string().min(1),
226
+ installStatus: z.enum(["metadata-only", "installable"]),
227
+ installNote: z.string().min(1)
228
+ });
229
+ const codexPluginManifestSchema = z.object({
230
+ name: trustedSourceNameSchema,
231
+ version: z.string().min(1),
232
+ description: z.string().min(1),
233
+ repository: z.string().url(),
234
+ license: z.string().min(1),
235
+ skills: z.string().min(1)
236
+ }).passthrough();
237
+ const trustedSourceSkillSummarySchema = z.strictObject({
238
+ name: skillNameSchema,
239
+ description: z.string().min(1),
240
+ hasResources: z.boolean()
241
+ });
242
+ //#endregion
201
243
  //#region src/config/schema.ts
202
244
  /**
203
245
  * Targets stay free-form strings on purpose: third-party adapters should be
@@ -205,12 +247,21 @@ const packDefinitionSchema = z.strictObject({
205
247
  */
206
248
  const agentyxTargetSchema = z.string().min(1, "Targets must be non-empty strings.");
207
249
  const enabledCapabilityNameSchema = z.string().min(1, "Enabled capability names must be non-empty strings.").regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Enabled capability names must be lowercase kebab-case, for example \"rtk\".");
250
+ /**
251
+ * Portable project-relative path to a directory whose direct children are Agent Skills.
252
+ * Backslashes, absolute paths and parent traversal are rejected so the same config is safe on
253
+ * every supported platform.
254
+ */
255
+ const skillDirectorySchema = z.string().min(1, "Skill directories must be non-empty strings.").regex(/^(?!\/)(?![A-Za-z]:)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/, "Skill directories must be portable project-relative paths without parent traversal.");
208
256
  /** The `.agentyx.json` project configuration. */
209
257
  const agentyxConfigSchema = z.strictObject({
210
258
  $schema: z.string().min(1, "$schema must be a non-empty string.").describe("Optional path or URL to the Agentyx JSON Schema.").optional(),
211
259
  packs: z.array(packNameSchema).describe("Capability packs this project selects.").default([]),
212
260
  enable: z.array(enabledCapabilityNameSchema).describe("Optional capabilities to activate by explicit identifier.").default([]),
213
- targets: z.array(agentyxTargetSchema).describe("Coding-agent providers this project targets.").default([])
261
+ targets: z.array(agentyxTargetSchema).describe("Coding-agent providers this project targets.").default([]),
262
+ skillDirectories: z.array(skillDirectorySchema).describe("Project-relative roots containing local Agent Skills.").optional(),
263
+ localPacks: z.array(packDefinitionSchema).describe("Project-owned packs that can reference built-in or local Skills.").optional(),
264
+ trustedSources: z.array(trustedSourceReferenceSchema).describe("Pinned local checkouts of known external skill/plugin sources.").optional()
214
265
  });
215
266
  //#endregion
216
267
  //#region src/config/json-schema.ts
@@ -281,163 +332,6 @@ function isFileNotFound(cause) {
281
332
  return cause instanceof Error && cause.code === "ENOENT";
282
333
  }
283
334
  //#endregion
284
- //#region src/mcp/errors.ts
285
- var UnknownMcpServerError = class extends AgentyxError {
286
- serverName;
287
- requiredBy;
288
- knownServers;
289
- constructor(serverName, requiredBy, knownServers) {
290
- const origin = requiredBy === void 0 ? "" : ` (required by "${requiredBy}")`;
291
- const known = knownServers.length > 0 ? [...knownServers].sort().join(", ") : "none";
292
- super("unknown_mcp_server", `Unknown MCP server "${serverName}"${origin}. Known MCP servers: ${known}.`);
293
- this.name = "UnknownMcpServerError";
294
- this.serverName = serverName;
295
- this.requiredBy = requiredBy;
296
- this.knownServers = knownServers;
297
- }
298
- };
299
- var DuplicateMcpServerError = class extends AgentyxError {
300
- serverName;
301
- constructor(serverName) {
302
- super("duplicate_mcp_server", `Duplicate MCP server definition: "${serverName}".`);
303
- this.name = "DuplicateMcpServerError";
304
- this.serverName = serverName;
305
- }
306
- };
307
- var InvalidMcpServerError = class extends AgentyxError {
308
- origin;
309
- reason;
310
- constructor(origin, reason, options) {
311
- const detail = typeof reason === "string" ? reason : formatIssues$1(reason);
312
- super("invalid_mcp_server", `Invalid MCP server in ${origin}: ${detail}`, options);
313
- this.name = "InvalidMcpServerError";
314
- this.origin = origin;
315
- this.reason = detail;
316
- }
317
- };
318
- function formatIssues$1(error) {
319
- return error.issues.map((issue) => {
320
- const path = issue.path.map(String).join(".");
321
- return path === "" ? issue.message : `${path}: ${issue.message}`;
322
- }).join("; ");
323
- }
324
- //#endregion
325
- //#region src/mcp/registry.ts
326
- function createMcpServerRegistry(sources) {
327
- const byName = /* @__PURE__ */ new Map();
328
- for (const source of sources) {
329
- const name = mcpServerNameSchema.safeParse(source.name);
330
- if (!name.success) throw new InvalidMcpServerError(`MCP server source "${source.name}"`, name.error);
331
- if (byName.has(name.data)) throw new DuplicateMcpServerError(name.data);
332
- byName.set(name.data, source);
333
- }
334
- const names = [...byName.keys()];
335
- const loaded = /* @__PURE__ */ new Map();
336
- const get = (name) => {
337
- const cached = loaded.get(name);
338
- if (cached !== void 0) return cached;
339
- const source = byName.get(name);
340
- if (source === void 0) throw new UnknownMcpServerError(name, void 0, names);
341
- const origin = `MCP server "${name}"`;
342
- const server = mcpServerDefinitionSchema.safeParse(source.load());
343
- if (!server.success) throw new InvalidMcpServerError(origin, server.error);
344
- if (server.data.name !== name) throw new InvalidMcpServerError(origin, `it declares the name "${server.data.name}"`);
345
- loaded.set(name, server.data);
346
- return server.data;
347
- };
348
- return {
349
- names,
350
- has: (name) => byName.has(name),
351
- listMetadata: () => names.map((name) => {
352
- const server = get(name);
353
- return {
354
- name: server.name,
355
- description: server.description,
356
- transport: server.transport,
357
- contextCost: server.contextCost
358
- };
359
- }),
360
- get
361
- };
362
- }
363
- const builtInMcpServerRegistry = createMcpServerRegistry([
364
- {
365
- name: "context7",
366
- load: () => ({
367
- name: "context7",
368
- description: "Fetch up-to-date library documentation from Context7.",
369
- transport: "http",
370
- contextCost: "medium",
371
- url: "https://mcp.context7.com/mcp"
372
- })
373
- },
374
- {
375
- name: "playwright",
376
- load: () => ({
377
- name: "playwright",
378
- description: "Automate and inspect browsers through Playwright MCP.",
379
- transport: "stdio",
380
- contextCost: "high",
381
- command: "npx",
382
- args: ["@playwright/mcp@latest"]
383
- })
384
- },
385
- {
386
- name: "codebase-memory",
387
- load: () => ({
388
- name: "codebase-memory",
389
- description: "Structural code-intelligence MCP backed by a persistent code knowledge graph.",
390
- transport: "stdio",
391
- contextCost: "high",
392
- command: "codebase-memory-mcp"
393
- })
394
- },
395
- {
396
- name: "github",
397
- load: () => ({
398
- name: "github",
399
- description: "Read repositories, issues, pull requests and workflow runs on GitHub.",
400
- transport: "http",
401
- contextCost: "high",
402
- url: "https://api.githubcopilot.com/mcp/"
403
- })
404
- },
405
- {
406
- name: "sentry",
407
- load: () => ({
408
- name: "sentry",
409
- description: "Inspect production issues, events and stack traces recorded by Sentry.",
410
- transport: "http",
411
- contextCost: "medium",
412
- url: "https://mcp.sentry.dev/mcp"
413
- })
414
- },
415
- {
416
- name: "chrome-devtools",
417
- load: () => ({
418
- name: "chrome-devtools",
419
- description: "Record performance traces and inspect pages through Chrome DevTools.",
420
- transport: "stdio",
421
- contextCost: "high",
422
- command: "npx",
423
- args: ["-y", "chrome-devtools-mcp@latest"]
424
- })
425
- },
426
- {
427
- name: "supabase",
428
- load: () => ({
429
- name: "supabase",
430
- description: "Inspect and query Supabase project schemas, tables and logs.",
431
- transport: "stdio",
432
- contextCost: "high",
433
- command: "npx",
434
- args: ["-y", "@supabase/mcp-server-supabase@latest"],
435
- env: { SUPABASE_ACCESS_TOKEN: { fromEnv: "SUPABASE_ACCESS_TOKEN" } }
436
- })
437
- }
438
- ]);
439
- const builtInMcpServerNames = builtInMcpServerRegistry.names;
440
- //#endregion
441
335
  //#region src/pack/errors.ts
442
336
  /** Raised when a requested pack is not present in the registry. */
443
337
  var UnknownPackError = class extends AgentyxError {
@@ -688,54 +582,6 @@ const builtInPacks = [
688
582
  /** The registry used by default when no explicit registry is supplied. */
689
583
  const builtInPackRegistry = createPackRegistry(builtInPacks);
690
584
  //#endregion
691
- //#region src/pack/resolver.ts
692
- /**
693
- * Resolves selected packs without hidden inheritance.
694
- *
695
- * The result preserves configured order, removes duplicates by first
696
- * occurrence, and validates every requested pack.
697
- *
698
- * @throws {UnknownPackError} when a requested pack is missing.
699
- */
700
- function resolvePacks(requestedPacks, registry = builtInPackRegistry) {
701
- const resolved = [];
702
- const seen = /* @__PURE__ */ new Set();
703
- for (const name of requestedPacks) {
704
- if (seen.has(name)) continue;
705
- if (!registry.has(name)) throw new UnknownPackError(name, void 0, [...registry.keys()]);
706
- seen.add(name);
707
- resolved.push(name);
708
- }
709
- return resolved;
710
- }
711
- //#endregion
712
- //#region src/mcp/resolver.ts
713
- function collectPackMcpServerReferences(resolvedPacks, packRegistry, mcpRegistry) {
714
- const servers = [];
715
- const seen = /* @__PURE__ */ new Set();
716
- for (const packName of resolvedPacks) for (const server of packRegistry.get(packName)?.mcpServers ?? []) {
717
- const serverName = server.name;
718
- if (seen.has(serverName)) continue;
719
- if (!mcpRegistry.has(serverName)) throw new UnknownMcpServerError(serverName, packName, mcpRegistry.names);
720
- seen.add(serverName);
721
- servers.push(server);
722
- }
723
- return servers;
724
- }
725
- function filterEffectiveMcpServers(servers, enabledCapabilities) {
726
- const enabled = new Set(enabledCapabilities);
727
- return servers.filter((server) => server.activation === "default" || enabled.has(server.name)).map((server) => server.name);
728
- }
729
- function collectPackMcpServers(resolvedPacks, packRegistry, mcpRegistry, enabledCapabilities = []) {
730
- return filterEffectiveMcpServers(collectPackMcpServerReferences(resolvedPacks, packRegistry, mcpRegistry), enabledCapabilities);
731
- }
732
- function resolvePackMcpServerReferences(requestedPacks, packRegistry = builtInPackRegistry, mcpRegistry = builtInMcpServerRegistry) {
733
- return collectPackMcpServerReferences(resolvePacks(requestedPacks, packRegistry), packRegistry, mcpRegistry);
734
- }
735
- function resolvePackMcpServers(requestedPacks, packRegistry = builtInPackRegistry, mcpRegistry = builtInMcpServerRegistry, enabledCapabilities = []) {
736
- return collectPackMcpServers(resolvePacks(requestedPacks, packRegistry), packRegistry, mcpRegistry, enabledCapabilities);
737
- }
738
- //#endregion
739
585
  //#region src/assets.ts
740
586
  /**
741
587
  * Location of the non-code assets that ship with `@agentyx/core`.
@@ -795,14 +641,14 @@ var InvalidSkillError = class extends AgentyxError {
795
641
  origin;
796
642
  reason;
797
643
  constructor(origin, reason, options) {
798
- const detail = typeof reason === "string" ? reason : formatIssues(reason);
644
+ const detail = typeof reason === "string" ? reason : formatIssues$1(reason);
799
645
  super("invalid_skill", `Invalid skill in ${origin}: ${detail}`, options);
800
646
  this.name = "InvalidSkillError";
801
647
  this.origin = origin;
802
648
  this.reason = detail;
803
649
  }
804
650
  };
805
- function formatIssues(error) {
651
+ function formatIssues$1(error) {
806
652
  return error.issues.map((issue) => {
807
653
  const path = issue.path.map(String).join(".");
808
654
  return path === "" ? issue.message : `${path}: ${issue.message}`;
@@ -1021,6 +867,338 @@ function loadBuiltInSkill(name) {
1021
867
  return parseSkillMarkdown(markdown, filePath);
1022
868
  }
1023
869
  //#endregion
870
+ //#region src/source/errors.ts
871
+ var DuplicateTrustedSourceError = class extends AgentyxError {
872
+ sourceName;
873
+ constructor(sourceName) {
874
+ super("duplicate_trusted_source", `Duplicate trusted source "${sourceName}".`);
875
+ this.name = "DuplicateTrustedSourceError";
876
+ this.sourceName = sourceName;
877
+ }
878
+ };
879
+ var UnknownTrustedSourceError = class extends AgentyxError {
880
+ sourceName;
881
+ knownSources;
882
+ constructor(sourceName, knownSources) {
883
+ const known = knownSources.length > 0 ? [...knownSources].sort().join(", ") : "none";
884
+ super("unknown_trusted_source", `Unknown trusted source "${sourceName}". Known trusted sources: ${known}.`);
885
+ this.name = "UnknownTrustedSourceError";
886
+ this.sourceName = sourceName;
887
+ this.knownSources = knownSources;
888
+ }
889
+ };
890
+ var TrustedSourceLoadError = class extends AgentyxError {
891
+ sourceName;
892
+ constructor(sourceName, reason, options) {
893
+ super("trusted_source_load_error", `Could not load trusted source "${sourceName}": ${reason}`, options);
894
+ this.name = "TrustedSourceLoadError";
895
+ this.sourceName = sourceName;
896
+ }
897
+ };
898
+ //#endregion
899
+ //#region src/source/registry.ts
900
+ const knownTrustedSources = [trustedSourceDefinitionSchema.parse({
901
+ name: "superpowers",
902
+ displayName: "Superpowers",
903
+ repository: "https://github.com/obra/superpowers",
904
+ type: "codex-plugin",
905
+ manifestPath: ".codex-plugin/plugin.json",
906
+ recommendedPath: ".agentyx/sources/superpowers",
907
+ description: "Agentic planning, TDD, debugging, code review and delivery workflows packaged as a Codex plugin.",
908
+ installStatus: "metadata-only",
909
+ installNote: "Agentyx can inspect and verify the local plugin checkout, but does not install its resource-bearing skills yet."
910
+ })];
911
+ const knownTrustedSourceRegistry = createTrustedSourceRegistry(knownTrustedSources);
912
+ function createTrustedSourceRegistry(definitions) {
913
+ const registry = /* @__PURE__ */ new Map();
914
+ for (const definition of definitions) {
915
+ const parsed = trustedSourceDefinitionSchema.parse(definition);
916
+ if (registry.has(parsed.name)) throw new DuplicateTrustedSourceError(parsed.name);
917
+ registry.set(parsed.name, parsed);
918
+ }
919
+ return registry;
920
+ }
921
+ function getTrustedSourceDefinition(source, registry = knownTrustedSourceRegistry) {
922
+ const name = typeof source === "string" ? source : source.name;
923
+ const definition = registry.get(name);
924
+ if (definition === void 0) throw new UnknownTrustedSourceError(name, [...registry.keys()]);
925
+ return definition;
926
+ }
927
+ //#endregion
928
+ //#region src/config/project.ts
929
+ /**
930
+ * Loads `.agentyx.json` and any checked-in Agent Skills it declares.
931
+ *
932
+ * A Skill root contains one directory per Skill, each with a `SKILL.md`. Roots must resolve inside
933
+ * the project even through symlinks. Loading is local-only: this function never clones a repository
934
+ * or accesses the network.
935
+ */
936
+ async function loadAgentyxProject(projectPath = process.cwd()) {
937
+ const projectDir = resolve(projectPath);
938
+ const config = await loadAgentyxConfig(projectDir);
939
+ for (const source of config.trustedSources ?? []) getTrustedSourceDefinition(source);
940
+ const localSources = await loadLocalSkillSources(projectDir, config.skillDirectories ?? []);
941
+ const skillRegistry = createSkillRegistry([...builtInSkillRegistry.names.map((name) => ({
942
+ name,
943
+ load: () => builtInSkillRegistry.get(name)
944
+ })), ...localSources]);
945
+ return {
946
+ config,
947
+ packRegistry: config.localPacks === void 0 ? builtInPackRegistry : createPackRegistry([...builtInPacks, ...config.localPacks]),
948
+ skillRegistry
949
+ };
950
+ }
951
+ async function loadLocalSkillSources(projectDir, directories) {
952
+ const projectRealPath = await realpath(projectDir);
953
+ const sources = [];
954
+ for (const directory of directories) {
955
+ const root = resolve(projectDir, directory);
956
+ let rootRealPath;
957
+ try {
958
+ rootRealPath = await realpath(root);
959
+ } catch (cause) {
960
+ throw localDirectoryError(directory, "the directory does not exist or cannot be read", cause);
961
+ }
962
+ if (!isInside$1(rootRealPath, projectRealPath)) throw new LocalSkillDirectoryError(directory, "the resolved path is outside the project");
963
+ let entries;
964
+ try {
965
+ entries = await readdir(rootRealPath, { withFileTypes: true });
966
+ } catch (cause) {
967
+ throw localDirectoryError(directory, "the directory cannot be listed", cause);
968
+ }
969
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
970
+ if (!entry.isDirectory()) continue;
971
+ const filePath = join(rootRealPath, entry.name, "SKILL.md");
972
+ let markdown;
973
+ try {
974
+ markdown = await readFile(filePath, "utf8");
975
+ } catch (cause) {
976
+ if (cause instanceof Error && cause.code === "ENOENT") continue;
977
+ throw localDirectoryError(directory, `cannot read ${entry.name}/SKILL.md`, cause);
978
+ }
979
+ const skill = parseSkillMarkdown(markdown, filePath);
980
+ if (skill.name !== entry.name) throw new LocalSkillDirectoryError(directory, `${entry.name}/SKILL.md declares the name "${skill.name}"`);
981
+ sources.push({
982
+ name: skill.name,
983
+ load: () => skill
984
+ });
985
+ }
986
+ }
987
+ return sources;
988
+ }
989
+ function isInside$1(path, root) {
990
+ const pathFromRoot = relative(root, path);
991
+ return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep}`) && pathFromRoot !== ".." && !isAbsolute(pathFromRoot);
992
+ }
993
+ function localDirectoryError(directory, reason, cause) {
994
+ return new LocalSkillDirectoryError(directory, reason, cause instanceof Error ? { cause } : void 0);
995
+ }
996
+ //#endregion
997
+ //#region src/mcp/errors.ts
998
+ var UnknownMcpServerError = class extends AgentyxError {
999
+ serverName;
1000
+ requiredBy;
1001
+ knownServers;
1002
+ constructor(serverName, requiredBy, knownServers) {
1003
+ const origin = requiredBy === void 0 ? "" : ` (required by "${requiredBy}")`;
1004
+ const known = knownServers.length > 0 ? [...knownServers].sort().join(", ") : "none";
1005
+ super("unknown_mcp_server", `Unknown MCP server "${serverName}"${origin}. Known MCP servers: ${known}.`);
1006
+ this.name = "UnknownMcpServerError";
1007
+ this.serverName = serverName;
1008
+ this.requiredBy = requiredBy;
1009
+ this.knownServers = knownServers;
1010
+ }
1011
+ };
1012
+ var DuplicateMcpServerError = class extends AgentyxError {
1013
+ serverName;
1014
+ constructor(serverName) {
1015
+ super("duplicate_mcp_server", `Duplicate MCP server definition: "${serverName}".`);
1016
+ this.name = "DuplicateMcpServerError";
1017
+ this.serverName = serverName;
1018
+ }
1019
+ };
1020
+ var InvalidMcpServerError = class extends AgentyxError {
1021
+ origin;
1022
+ reason;
1023
+ constructor(origin, reason, options) {
1024
+ const detail = typeof reason === "string" ? reason : formatIssues(reason);
1025
+ super("invalid_mcp_server", `Invalid MCP server in ${origin}: ${detail}`, options);
1026
+ this.name = "InvalidMcpServerError";
1027
+ this.origin = origin;
1028
+ this.reason = detail;
1029
+ }
1030
+ };
1031
+ function formatIssues(error) {
1032
+ return error.issues.map((issue) => {
1033
+ const path = issue.path.map(String).join(".");
1034
+ return path === "" ? issue.message : `${path}: ${issue.message}`;
1035
+ }).join("; ");
1036
+ }
1037
+ //#endregion
1038
+ //#region src/mcp/registry.ts
1039
+ function createMcpServerRegistry(sources) {
1040
+ const byName = /* @__PURE__ */ new Map();
1041
+ for (const source of sources) {
1042
+ const name = mcpServerNameSchema.safeParse(source.name);
1043
+ if (!name.success) throw new InvalidMcpServerError(`MCP server source "${source.name}"`, name.error);
1044
+ if (byName.has(name.data)) throw new DuplicateMcpServerError(name.data);
1045
+ byName.set(name.data, source);
1046
+ }
1047
+ const names = [...byName.keys()];
1048
+ const loaded = /* @__PURE__ */ new Map();
1049
+ const get = (name) => {
1050
+ const cached = loaded.get(name);
1051
+ if (cached !== void 0) return cached;
1052
+ const source = byName.get(name);
1053
+ if (source === void 0) throw new UnknownMcpServerError(name, void 0, names);
1054
+ const origin = `MCP server "${name}"`;
1055
+ const server = mcpServerDefinitionSchema.safeParse(source.load());
1056
+ if (!server.success) throw new InvalidMcpServerError(origin, server.error);
1057
+ if (server.data.name !== name) throw new InvalidMcpServerError(origin, `it declares the name "${server.data.name}"`);
1058
+ loaded.set(name, server.data);
1059
+ return server.data;
1060
+ };
1061
+ return {
1062
+ names,
1063
+ has: (name) => byName.has(name),
1064
+ listMetadata: () => names.map((name) => {
1065
+ const server = get(name);
1066
+ return {
1067
+ name: server.name,
1068
+ description: server.description,
1069
+ transport: server.transport,
1070
+ contextCost: server.contextCost
1071
+ };
1072
+ }),
1073
+ get
1074
+ };
1075
+ }
1076
+ const builtInMcpServerRegistry = createMcpServerRegistry([
1077
+ {
1078
+ name: "context7",
1079
+ load: () => ({
1080
+ name: "context7",
1081
+ description: "Fetch up-to-date library documentation from Context7.",
1082
+ transport: "http",
1083
+ contextCost: "medium",
1084
+ url: "https://mcp.context7.com/mcp"
1085
+ })
1086
+ },
1087
+ {
1088
+ name: "playwright",
1089
+ load: () => ({
1090
+ name: "playwright",
1091
+ description: "Automate and inspect browsers through Playwright MCP.",
1092
+ transport: "stdio",
1093
+ contextCost: "high",
1094
+ command: "npx",
1095
+ args: ["@playwright/mcp@latest"]
1096
+ })
1097
+ },
1098
+ {
1099
+ name: "codebase-memory",
1100
+ load: () => ({
1101
+ name: "codebase-memory",
1102
+ description: "Structural code-intelligence MCP backed by a persistent code knowledge graph.",
1103
+ transport: "stdio",
1104
+ contextCost: "high",
1105
+ command: "codebase-memory-mcp"
1106
+ })
1107
+ },
1108
+ {
1109
+ name: "github",
1110
+ load: () => ({
1111
+ name: "github",
1112
+ description: "Read repositories, issues, pull requests and workflow runs on GitHub.",
1113
+ transport: "http",
1114
+ contextCost: "high",
1115
+ url: "https://api.githubcopilot.com/mcp/"
1116
+ })
1117
+ },
1118
+ {
1119
+ name: "sentry",
1120
+ load: () => ({
1121
+ name: "sentry",
1122
+ description: "Inspect production issues, events and stack traces recorded by Sentry.",
1123
+ transport: "http",
1124
+ contextCost: "medium",
1125
+ url: "https://mcp.sentry.dev/mcp"
1126
+ })
1127
+ },
1128
+ {
1129
+ name: "chrome-devtools",
1130
+ load: () => ({
1131
+ name: "chrome-devtools",
1132
+ description: "Record performance traces and inspect pages through Chrome DevTools.",
1133
+ transport: "stdio",
1134
+ contextCost: "high",
1135
+ command: "npx",
1136
+ args: ["-y", "chrome-devtools-mcp@latest"]
1137
+ })
1138
+ },
1139
+ {
1140
+ name: "supabase",
1141
+ load: () => ({
1142
+ name: "supabase",
1143
+ description: "Inspect and query Supabase project schemas, tables and logs.",
1144
+ transport: "stdio",
1145
+ contextCost: "high",
1146
+ command: "npx",
1147
+ args: ["-y", "@supabase/mcp-server-supabase@latest"],
1148
+ env: { SUPABASE_ACCESS_TOKEN: { fromEnv: "SUPABASE_ACCESS_TOKEN" } }
1149
+ })
1150
+ }
1151
+ ]);
1152
+ const builtInMcpServerNames = builtInMcpServerRegistry.names;
1153
+ //#endregion
1154
+ //#region src/pack/resolver.ts
1155
+ /**
1156
+ * Resolves selected packs without hidden inheritance.
1157
+ *
1158
+ * The result preserves configured order, removes duplicates by first
1159
+ * occurrence, and validates every requested pack.
1160
+ *
1161
+ * @throws {UnknownPackError} when a requested pack is missing.
1162
+ */
1163
+ function resolvePacks(requestedPacks, registry = builtInPackRegistry) {
1164
+ const resolved = [];
1165
+ const seen = /* @__PURE__ */ new Set();
1166
+ for (const name of requestedPacks) {
1167
+ if (seen.has(name)) continue;
1168
+ if (!registry.has(name)) throw new UnknownPackError(name, void 0, [...registry.keys()]);
1169
+ seen.add(name);
1170
+ resolved.push(name);
1171
+ }
1172
+ return resolved;
1173
+ }
1174
+ //#endregion
1175
+ //#region src/mcp/resolver.ts
1176
+ function collectPackMcpServerReferences(resolvedPacks, packRegistry, mcpRegistry) {
1177
+ const servers = [];
1178
+ const seen = /* @__PURE__ */ new Set();
1179
+ for (const packName of resolvedPacks) for (const server of packRegistry.get(packName)?.mcpServers ?? []) {
1180
+ const serverName = server.name;
1181
+ if (seen.has(serverName)) continue;
1182
+ if (!mcpRegistry.has(serverName)) throw new UnknownMcpServerError(serverName, packName, mcpRegistry.names);
1183
+ seen.add(serverName);
1184
+ servers.push(server);
1185
+ }
1186
+ return servers;
1187
+ }
1188
+ function filterEffectiveMcpServers(servers, enabledCapabilities) {
1189
+ const enabled = new Set(enabledCapabilities);
1190
+ return servers.filter((server) => server.activation === "default" || enabled.has(server.name)).map((server) => server.name);
1191
+ }
1192
+ function collectPackMcpServers(resolvedPacks, packRegistry, mcpRegistry, enabledCapabilities = []) {
1193
+ return filterEffectiveMcpServers(collectPackMcpServerReferences(resolvedPacks, packRegistry, mcpRegistry), enabledCapabilities);
1194
+ }
1195
+ function resolvePackMcpServerReferences(requestedPacks, packRegistry = builtInPackRegistry, mcpRegistry = builtInMcpServerRegistry) {
1196
+ return collectPackMcpServerReferences(resolvePacks(requestedPacks, packRegistry), packRegistry, mcpRegistry);
1197
+ }
1198
+ function resolvePackMcpServers(requestedPacks, packRegistry = builtInPackRegistry, mcpRegistry = builtInMcpServerRegistry, enabledCapabilities = []) {
1199
+ return collectPackMcpServers(resolvePacks(requestedPacks, packRegistry), packRegistry, mcpRegistry, enabledCapabilities);
1200
+ }
1201
+ //#endregion
1024
1202
  //#region src/skill/resolver.ts
1025
1203
  /**
1026
1204
  * Collects the skills contributed by an already-resolved pack chain.
@@ -1167,7 +1345,6 @@ function resolvePackTools(requestedPacks, packRegistry = builtInPackRegistry, to
1167
1345
  * The input is never mutated.
1168
1346
  *
1169
1347
  * @throws {UnknownPackError} when a configured pack is missing.
1170
- * @throws {CircularPackDependencyError} when inheritance forms a cycle.
1171
1348
  * @throws {UnknownSkillError} when a pack references an unknown skill.
1172
1349
  */
1173
1350
  function resolveAgentyxConfig(config, registry = builtInPackRegistry, skillRegistry = builtInSkillRegistry, mcpRegistry = builtInMcpServerRegistry, toolRegistry = builtInToolRegistry) {
@@ -1527,6 +1704,94 @@ function isNotFound(cause) {
1527
1704
  return cause instanceof Error && cause.code === "ENOENT";
1528
1705
  }
1529
1706
  //#endregion
1530
- export { AGENTYX_CONFIG_FILENAME, AGENTYX_CONFIG_SCHEMA_ID, AGENTYX_MANIFEST_FILENAME, AgentyxConfigNotFoundError, AgentyxConfigParseError, AgentyxConfigValidationError, AgentyxError, AgentyxManifestParseError, AgentyxManifestValidationError, CircularPackDependencyError, DuplicateMcpServerError, DuplicatePackError, DuplicateSkillError, DuplicateToolError, INSTALL_MANIFEST_VERSION, InvalidMcpServerError, InvalidSkillError, InvalidToolError, MCP_CAPABILITY_LEVELS, MCP_CONTEXT_COSTS, PACKAGE_MANAGERS, PACK_CATEGORIES, TOOL_ACTIVATION_LEVELS, UnknownEnabledCapabilityError, UnknownMcpServerError, UnknownPackError, UnknownSkillError, UnknownToolError, agentyxConfigPath, agentyxConfigSchema, agentyxCoreName, agentyxManifestPath, agentyxTargetSchema, buildAgentyxConfig, buildAgentyxConfigJsonSchema, builtInMcpServerNames, builtInMcpServerRegistry, builtInPackRegistry, builtInPacks, builtInSkillNames, builtInSkillRegistry, builtInToolNames, builtInToolRegistry, collectPackMcpServerReferences, collectPackMcpServers, collectPackToolReferences, createMcpServerRegistry, createPackRegistry, createSkillRegistry, createToolRegistry, detectProject, emptyInstallManifest, enabledCapabilityNameSchema, filterEffectiveMcpServers, filterEffectiveTools, formatAgentyxConfig, formatInstallManifest, formatSkillMarkdown, getCoreStatus, hashContent, installManifestEntrySchema, installManifestSchema, loadAgentyxConfig, loadInstallManifest, manifestEntriesByPath, mcpCapabilityLevelSchema, mcpContextCostSchema, mcpEnvReferenceSchema, mcpManifestEntrySchema, mcpServerDefinitionSchema, mcpServerReferenceSchema, packCategorySchema, packDefinitionSchema, packNameSchema, parseAgentyxConfig, parseInstallManifest, parseSkillMarkdown, resolveAgentyxConfig, resolvePackMcpServerReferences, resolvePackMcpServers, resolvePackSkills, resolvePackToolReferences, resolvePackTools, resolvePacks, skillDefinitionSchema, skillManifestEntrySchema, toolActivationLevelSchema, toolDefinitionSchema, toolNameSchema, toolReferenceSchema };
1707
+ //#region src/source/inspection.ts
1708
+ async function inspectTrustedSource(projectPath, reference) {
1709
+ const definition = getTrustedSourceDefinition(reference);
1710
+ const projectDir = resolve(projectPath);
1711
+ const projectRealPath = await realpath(projectDir);
1712
+ const root = resolve(projectDir, reference.path);
1713
+ const rootRealPath = await realpathOrThrow(reference.name, root, "the checkout path cannot be read");
1714
+ if (!isInside(rootRealPath, projectRealPath)) throw new TrustedSourceLoadError(reference.name, "the checkout path resolves outside the project");
1715
+ const manifestPath = join(rootRealPath, definition.manifestPath);
1716
+ const manifest = await readManifest(reference.name, manifestPath);
1717
+ if (manifest.name !== definition.name) throw new TrustedSourceLoadError(reference.name, `${definition.manifestPath} declares the name "${manifest.name}"`);
1718
+ if (manifest.repository !== definition.repository) throw new TrustedSourceLoadError(reference.name, `${definition.manifestPath} declares repository "${manifest.repository}"`);
1719
+ const skillsPath = resolve(dirname(manifestPath), manifest.skills);
1720
+ if (!isInside(skillsPath, rootRealPath)) throw new TrustedSourceLoadError(reference.name, "the manifest skills path resolves outside the checkout");
1721
+ const skillsRealPath = await realpathOrThrow(reference.name, skillsPath, "the manifest skills path cannot be read");
1722
+ if (!isInside(skillsRealPath, rootRealPath)) throw new TrustedSourceLoadError(reference.name, "the manifest skills path resolves outside the checkout");
1723
+ const skills = await inspectSkillSummaries(reference.name, skillsRealPath);
1724
+ return {
1725
+ definition,
1726
+ reference,
1727
+ rootPath: rootRealPath,
1728
+ manifest,
1729
+ skillsPath: skillsRealPath,
1730
+ skills,
1731
+ installable: definition.installStatus === "installable" && skills.every((skill) => !skill.hasResources),
1732
+ installNote: definition.installNote
1733
+ };
1734
+ }
1735
+ async function readManifest(sourceName, path) {
1736
+ let raw;
1737
+ try {
1738
+ raw = await readFile(path, "utf8");
1739
+ } catch (cause) {
1740
+ throw trustedSourceLoadError(sourceName, "the plugin manifest cannot be read", cause);
1741
+ }
1742
+ try {
1743
+ return codexPluginManifestSchema.parse(JSON.parse(raw));
1744
+ } catch (cause) {
1745
+ throw trustedSourceLoadError(sourceName, "the plugin manifest is invalid", cause);
1746
+ }
1747
+ }
1748
+ async function inspectSkillSummaries(sourceName, skillsPath) {
1749
+ let entries;
1750
+ try {
1751
+ entries = await readdir(skillsPath, { withFileTypes: true });
1752
+ } catch (cause) {
1753
+ throw trustedSourceLoadError(sourceName, "the plugin skills directory cannot be listed", cause);
1754
+ }
1755
+ const skills = [];
1756
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
1757
+ if (!entry.isDirectory()) continue;
1758
+ const skillRoot = join(skillsPath, entry.name);
1759
+ const skillPath = join(skillRoot, "SKILL.md");
1760
+ let markdown;
1761
+ try {
1762
+ markdown = await readFile(skillPath, "utf8");
1763
+ } catch (cause) {
1764
+ if (cause instanceof Error && cause.code === "ENOENT") continue;
1765
+ throw trustedSourceLoadError(sourceName, `cannot read ${entry.name}/SKILL.md`, cause);
1766
+ }
1767
+ const skill = parseSkillMarkdown(markdown, skillPath);
1768
+ if (skill.name !== entry.name) throw new TrustedSourceLoadError(sourceName, `${entry.name}/SKILL.md declares the name "${skill.name}"`);
1769
+ skills.push({
1770
+ name: skill.name,
1771
+ description: skill.description,
1772
+ hasResources: await hasResources(skillRoot)
1773
+ });
1774
+ }
1775
+ return skills;
1776
+ }
1777
+ async function hasResources(skillRoot) {
1778
+ return (await readdir(skillRoot, { withFileTypes: true })).some((entry) => entry.name !== "SKILL.md");
1779
+ }
1780
+ async function realpathOrThrow(sourceName, path, reason) {
1781
+ try {
1782
+ return await realpath(path);
1783
+ } catch (cause) {
1784
+ throw trustedSourceLoadError(sourceName, reason, cause);
1785
+ }
1786
+ }
1787
+ function isInside(path, root) {
1788
+ const pathFromRoot = relative(root, path);
1789
+ return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep}`) && pathFromRoot !== ".." && !isAbsolute(pathFromRoot);
1790
+ }
1791
+ function trustedSourceLoadError(sourceName, reason, cause) {
1792
+ return new TrustedSourceLoadError(sourceName, reason, cause instanceof Error ? { cause } : void 0);
1793
+ }
1794
+ //#endregion
1795
+ export { AGENTYX_CONFIG_FILENAME, AGENTYX_CONFIG_SCHEMA_ID, AGENTYX_MANIFEST_FILENAME, AgentyxConfigNotFoundError, AgentyxConfigParseError, AgentyxConfigValidationError, AgentyxError, AgentyxManifestParseError, AgentyxManifestValidationError, CircularPackDependencyError, DuplicateMcpServerError, DuplicatePackError, DuplicateSkillError, DuplicateToolError, DuplicateTrustedSourceError, INSTALL_MANIFEST_VERSION, InvalidMcpServerError, InvalidSkillError, InvalidToolError, LocalSkillDirectoryError, MCP_CAPABILITY_LEVELS, MCP_CONTEXT_COSTS, PACKAGE_MANAGERS, PACK_CATEGORIES, TOOL_ACTIVATION_LEVELS, TrustedSourceLoadError, UnknownEnabledCapabilityError, UnknownMcpServerError, UnknownPackError, UnknownSkillError, UnknownToolError, UnknownTrustedSourceError, agentyxConfigPath, agentyxConfigSchema, agentyxCoreName, agentyxManifestPath, agentyxTargetSchema, buildAgentyxConfig, buildAgentyxConfigJsonSchema, builtInMcpServerNames, builtInMcpServerRegistry, builtInPackRegistry, builtInPacks, builtInSkillNames, builtInSkillRegistry, builtInToolNames, builtInToolRegistry, codexPluginManifestSchema, collectPackMcpServerReferences, collectPackMcpServers, collectPackToolReferences, createMcpServerRegistry, createPackRegistry, createSkillRegistry, createToolRegistry, createTrustedSourceRegistry, detectProject, emptyInstallManifest, enabledCapabilityNameSchema, filterEffectiveMcpServers, filterEffectiveTools, formatAgentyxConfig, formatInstallManifest, formatSkillMarkdown, getCoreStatus, getTrustedSourceDefinition, hashContent, inspectTrustedSource, installManifestEntrySchema, installManifestSchema, knownTrustedSourceRegistry, knownTrustedSources, loadAgentyxConfig, loadAgentyxProject, loadInstallManifest, manifestEntriesByPath, mcpCapabilityLevelSchema, mcpContextCostSchema, mcpEnvReferenceSchema, mcpManifestEntrySchema, mcpServerDefinitionSchema, mcpServerReferenceSchema, packCategorySchema, packDefinitionSchema, packNameSchema, parseAgentyxConfig, parseInstallManifest, parseSkillMarkdown, resolveAgentyxConfig, resolvePackMcpServerReferences, resolvePackMcpServers, resolvePackSkills, resolvePackToolReferences, resolvePackTools, resolvePacks, skillDefinitionSchema, skillDirectorySchema, skillManifestEntrySchema, toolActivationLevelSchema, toolDefinitionSchema, toolNameSchema, toolReferenceSchema, trustedSourceDefinitionSchema, trustedSourceNameSchema, trustedSourcePathSchema, trustedSourceReferenceSchema, trustedSourceSkillSummarySchema };
1531
1796
 
1532
1797
  //# sourceMappingURL=index.mjs.map