@agentxm/extension-model 0.34.0 → 0.35.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.
@@ -427,6 +427,26 @@ export type ExtensionFqnParts = Schema.Schema.Type<typeof ExtensionFqnPartsSchem
427
427
  * @experimental This API is unstable and may change without notice.
428
428
  */
429
429
  export declare const parseExtensionFqnParts: (input: string) => ExtensionFqnParts | undefined;
430
+ /**
431
+ * A reference split into the name it identifies and the constraint appended
432
+ * to it. The constraint is everything after the first `@` that follows the
433
+ * last `/`, because the owner segment also starts with `@`; a trailing `@`
434
+ * yields an empty constraint for the caller to reject.
435
+ *
436
+ * @experimental This API is unstable and may change without notice.
437
+ */
438
+ export interface SplitExtensionReference {
439
+ readonly name: string;
440
+ readonly constraint: string | undefined;
441
+ }
442
+ /**
443
+ * Split `@owner/<plural>/name[@constraint]` into its name and constraint.
444
+ * This is the one place the separator between a name and its constraint is
445
+ * decided.
446
+ *
447
+ * @experimental This API is unstable and may change without notice.
448
+ */
449
+ export declare const splitExtensionReference: (input: string) => SplitExtensionReference;
430
450
  /**
431
451
  * Parse an extension spec string (with optional version constraint) into parts.
432
452
  * Strips the version constraint suffix and returns the validated FQN parts.
@@ -477,14 +497,6 @@ export declare const PackFqnSchema: Schema.String;
477
497
  * @experimental This API is unstable and may change without notice.
478
498
  */
479
499
  export type PackFqn = Schema.Schema.Type<typeof PackFqnSchema>;
480
- /**
481
- * Extension spec — fully qualified extension name with an optional version
482
- * constraint suffix. Accepts `@owner/type/name` or `@owner/type/name@constraint`
483
- * where the FQN portion validates through ExtensionFqnSchema and the optional
484
- * constraint validates as a semver VersionRange.
485
- *
486
- * @experimental This API is unstable and may change without notice.
487
- */
488
500
  export declare const ExtensionSpecSchema: Schema.brand<Schema.NonEmptyString, "ExtensionSpec">;
489
501
  /**
490
502
  * Inferred type for ExtensionSpec schema.
@@ -360,17 +360,26 @@ export const parseExtensionFqnParts = (input) => {
360
360
  return Result.isSuccess(result) ? result.success : undefined;
361
361
  };
362
362
  /**
363
- * Parse an extension spec string (with optional version constraint) into parts.
364
- * Strips the version constraint suffix and returns the validated FQN parts.
363
+ * Split `@owner/<plural>/name[@constraint]` into its name and constraint.
364
+ * This is the one place the separator between a name and its constraint is
365
+ * decided.
365
366
  *
366
367
  * @experimental This API is unstable and may change without notice.
367
368
  */
368
- export const parseExtensionSpecParts = (input) => {
369
+ export const splitExtensionReference = (input) => {
369
370
  const lastSlash = input.lastIndexOf("/");
370
371
  const constraintAt = lastSlash > 0 ? input.indexOf("@", lastSlash + 1) : -1;
371
- const fqnPart = constraintAt > 0 ? input.slice(0, constraintAt) : input;
372
- return parseExtensionFqnParts(fqnPart);
372
+ return constraintAt > 0
373
+ ? { name: input.slice(0, constraintAt), constraint: input.slice(constraintAt + 1) }
374
+ : { name: input, constraint: undefined };
373
375
  };
376
+ /**
377
+ * Parse an extension spec string (with optional version constraint) into parts.
378
+ * Strips the version constraint suffix and returns the validated FQN parts.
379
+ *
380
+ * @experimental This API is unstable and may change without notice.
381
+ */
382
+ export const parseExtensionSpecParts = (input) => parseExtensionFqnParts(splitExtensionReference(input).name);
374
383
  const INVALID_EXTENSION_FQN_MESSAGE = "Expected fully qualified name in @handle/(skills|mcps|subagents|rules|hooks|knowledge|packs)/name form";
375
384
  /**
376
385
  * Fully qualified name string schema validated against the composed handle,
@@ -425,24 +434,21 @@ export const PackFqnSchema = Schema.String.pipe(Schema.check(Schema.isPattern(PA
425
434
  *
426
435
  * @experimental This API is unstable and may change without notice.
427
436
  */
437
+ /** The constraint issue of a split reference, or none when it has none or it is valid. */
438
+ const constraintIssue = (constraint) => {
439
+ if (constraint === undefined)
440
+ return undefined;
441
+ const constraintResult = Schema.decodeUnknownResult(VersionRangeSchema)(constraint);
442
+ return Result.isFailure(constraintResult)
443
+ ? `Expected valid version constraint after @, got: ${constraint}`
444
+ : undefined;
445
+ };
428
446
  export const ExtensionSpecSchema = Schema.NonEmptyString.pipe(Schema.check(Schema.makeFilter((value) => {
429
- // Find the constraint separator: the @ after the last slash
430
- const lastSlash = value.lastIndexOf("/");
431
- const constraintAt = lastSlash > 0 ? value.indexOf("@", lastSlash + 1) : -1;
432
- const fqnPart = constraintAt > 0 ? value.slice(0, constraintAt) : value;
433
- const constraintPart = constraintAt > 0 ? value.slice(constraintAt + 1) : undefined;
434
- // Validate FQN portion
435
- if (parseExtensionFqnParts(fqnPart) === undefined) {
447
+ const { name, constraint } = splitExtensionReference(value);
448
+ if (parseExtensionFqnParts(name) === undefined) {
436
449
  return `Expected extension spec in @handle/type/name[@constraint] form, got: ${value}`;
437
450
  }
438
- // Validate constraint portion if present
439
- if (constraintPart !== undefined) {
440
- const constraintResult = Schema.decodeUnknownResult(VersionRangeSchema)(constraintPart);
441
- if (Result.isFailure(constraintResult)) {
442
- return `Expected valid version constraint after @, got: ${constraintPart}`;
443
- }
444
- }
445
- return undefined;
451
+ return constraintIssue(constraint);
446
452
  })), Schema.check(Schema.isPattern(EXTENSION_SPEC_PATTERN, {
447
453
  message: "Expected extension spec in @handle/type/name[@constraint] form",
448
454
  })), Schema.annotate({
@@ -460,20 +466,11 @@ export const ExtensionSpecSchema = Schema.NonEmptyString.pipe(Schema.check(Schem
460
466
  * @experimental This API is unstable and may change without notice.
461
467
  */
462
468
  export const PackSpecSchema = Schema.NonEmptyString.pipe(Schema.check(Schema.makeFilter((value) => {
463
- const lastSlash = value.lastIndexOf("/");
464
- const constraintAt = lastSlash > 0 ? value.indexOf("@", lastSlash + 1) : -1;
465
- const fqnPart = constraintAt > 0 ? value.slice(0, constraintAt) : value;
466
- const constraintPart = constraintAt > 0 ? value.slice(constraintAt + 1) : undefined;
467
- if (!PACK_FQN_PATTERN.test(fqnPart)) {
469
+ const { name, constraint } = splitExtensionReference(value);
470
+ if (!PACK_FQN_PATTERN.test(name)) {
468
471
  return `Expected pack spec in @handle/packs/name[@constraint] form, got: ${value}`;
469
472
  }
470
- if (constraintPart !== undefined) {
471
- const constraintResult = Schema.decodeUnknownResult(VersionRangeSchema)(constraintPart);
472
- if (Result.isFailure(constraintResult)) {
473
- return `Expected valid version constraint after @, got: ${constraintPart}`;
474
- }
475
- }
476
- return undefined;
473
+ return constraintIssue(constraint);
477
474
  })), Schema.check(Schema.isPattern(PACK_SPEC_PATTERN, {
478
475
  message: "Expected pack spec in @handle/packs/name[@constraint] form",
479
476
  })), Schema.annotate({
@@ -9,6 +9,9 @@
9
9
  * @experimental This API is unstable and may change without notice.
10
10
  */
11
11
  import * as Schema from "effect/Schema";
12
+ export declare const DeprecationReasons: readonly ["superseded", "obsolete", "unmaintained", "other"];
13
+ export declare const DeprecationReasonSchema: Schema.Literals<readonly ["superseded", "obsolete", "unmaintained", "other"]>;
14
+ export type DeprecationReason = typeof DeprecationReasonSchema.Type;
12
15
  export declare const DeprecationReplacementSchema: Schema.Union<readonly [Schema.Struct<{
13
16
  readonly status: Schema.Literal<"available">;
14
17
  readonly fqn: Schema.String;
@@ -18,7 +21,24 @@ export declare const DeprecationReplacementSchema: Schema.Union<readonly [Schema
18
21
  }>]>;
19
22
  export declare const DeprecationViewSchema: Schema.Union<readonly [Schema.Struct<{
20
23
  readonly deprecatedAt: Schema.decodeTo<Schema.DateTimeUtc, Schema.String, never, never>;
24
+ readonly reason: Schema.Literal<"superseded">;
25
+ readonly message: Schema.optional<Schema.String>;
26
+ readonly replacement: Schema.Union<readonly [Schema.Struct<{
27
+ readonly status: Schema.Literal<"available">;
28
+ readonly fqn: Schema.String;
29
+ }>, Schema.Struct<{
30
+ readonly status: Schema.Literal<"unavailable">;
31
+ readonly fqn: Schema.optional<Schema.String>;
32
+ }>]>;
33
+ }>, Schema.Struct<{
34
+ readonly deprecatedAt: Schema.decodeTo<Schema.DateTimeUtc, Schema.String, never, never>;
35
+ readonly reason: Schema.Literal<"obsolete">;
21
36
  readonly message: Schema.String;
37
+ readonly replacement: Schema.optional<Schema.Never>;
38
+ }>, Schema.Struct<{
39
+ readonly deprecatedAt: Schema.decodeTo<Schema.DateTimeUtc, Schema.String, never, never>;
40
+ readonly reason: Schema.Literal<"unmaintained">;
41
+ readonly message: Schema.optional<Schema.String>;
22
42
  readonly replacement: Schema.optional<Schema.Union<readonly [Schema.Struct<{
23
43
  readonly status: Schema.Literal<"available">;
24
44
  readonly fqn: Schema.String;
@@ -28,14 +48,15 @@ export declare const DeprecationViewSchema: Schema.Union<readonly [Schema.Struct
28
48
  }>]>>;
29
49
  }>, Schema.Struct<{
30
50
  readonly deprecatedAt: Schema.decodeTo<Schema.DateTimeUtc, Schema.String, never, never>;
31
- readonly message: Schema.optional<Schema.String>;
32
- readonly replacement: Schema.Union<readonly [Schema.Struct<{
51
+ readonly reason: Schema.Literal<"other">;
52
+ readonly message: Schema.String;
53
+ readonly replacement: Schema.optional<Schema.Union<readonly [Schema.Struct<{
33
54
  readonly status: Schema.Literal<"available">;
34
55
  readonly fqn: Schema.String;
35
56
  }>, Schema.Struct<{
36
57
  readonly status: Schema.Literal<"unavailable">;
37
58
  readonly fqn: Schema.optional<Schema.String>;
38
- }>]>;
59
+ }>]>>;
39
60
  }>]>;
40
61
  export type DeprecationReplacement = typeof DeprecationReplacementSchema.Type;
41
62
  export type DeprecationView = typeof DeprecationViewSchema.Type;
@@ -13,7 +13,12 @@ import { DateTimeUtcSchema } from "../date-time.js";
13
13
  import { ExtensionFqnSchema } from "./common.js";
14
14
  const DeprecationMessageSchema = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(500)).annotate({
15
15
  identifier: "DeprecationMessage",
16
- description: "Concise publisher guidance for consumers of a deprecated extension.",
16
+ description: "Optional publisher notes for consumers of a deprecated extension.",
17
+ });
18
+ export const DeprecationReasons = ["superseded", "obsolete", "unmaintained", "other"];
19
+ export const DeprecationReasonSchema = Schema.Literals(DeprecationReasons).annotate({
20
+ identifier: "DeprecationReason",
21
+ description: "The publisher's structured reason for deprecating an extension.",
17
22
  });
18
23
  export const DeprecationReplacementSchema = Schema.Union([
19
24
  Schema.Struct({
@@ -31,13 +36,27 @@ export const DeprecationReplacementSchema = Schema.Union([
31
36
  export const DeprecationViewSchema = Schema.Union([
32
37
  Schema.Struct({
33
38
  deprecatedAt: DateTimeUtcSchema,
39
+ reason: Schema.Literal("superseded"),
40
+ message: Schema.optional(DeprecationMessageSchema),
41
+ replacement: DeprecationReplacementSchema,
42
+ }),
43
+ Schema.Struct({
44
+ deprecatedAt: DateTimeUtcSchema,
45
+ reason: Schema.Literal("obsolete"),
34
46
  message: DeprecationMessageSchema,
35
- replacement: Schema.optional(DeprecationReplacementSchema),
47
+ replacement: Schema.optional(Schema.Never),
36
48
  }),
37
49
  Schema.Struct({
38
50
  deprecatedAt: DateTimeUtcSchema,
51
+ reason: Schema.Literal("unmaintained"),
39
52
  message: Schema.optional(DeprecationMessageSchema),
40
- replacement: DeprecationReplacementSchema,
53
+ replacement: Schema.optional(DeprecationReplacementSchema),
54
+ }),
55
+ Schema.Struct({
56
+ deprecatedAt: DateTimeUtcSchema,
57
+ reason: Schema.Literal("other"),
58
+ message: DeprecationMessageSchema,
59
+ replacement: Schema.optional(DeprecationReplacementSchema),
41
60
  }),
42
61
  ]).annotate({
43
62
  identifier: "DeprecationView",
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @experimental This API is unstable and may change without notice.
5
5
  */
6
- export { AgentIdSchema, type Author, AuthorSchema, CONTAINER_EXTENSION_TYPES, CommonManifestBaseFields, type ConfigurableAgentId, ConfigurableAgentIdSchema, type ContainerType, EXTENSION_NAME_PATTERN, INSTALLABLE_FROM_BY_TYPE, type ExtensionDependencyConstraintMap, ExtensionDependencyConstraintMapSchema, type ExtensionFqn, type ExtensionFqnParts, ExtensionFqnPartsSchema, ExtensionFqnSchema, type ExtensionName, ExtensionNameSchema, type ExtensionSpec, ExtensionSpecSchema, type ExtensionSourceFamily, type ExtensionType, type ExtensionTypePlural, ExtensionTypePluralSchema, ExtensionTypeSchema, type ExtensionVisibility, ExtensionVisibilitySchema, FQN_PATTERN, LicenseSchema, NON_PACK_FQN_PATTERN, type NonPackExtensionDependencyConstraintMap, NonPackExtensionDependencyConstraintMapSchema, type NonPackExtensionFqn, NonPackExtensionFqnSchema, type NonPackExtensionTypePlural, NonPackManifestFields, PACK_FQN_PATTERN, PER_AGENT_EXTENSION_TYPES, type PackFqn, PackFqnSchema, type PackMemberConstraint, PackMemberConstraintMapSchema, PackMemberConstraintSchema, type PackMemberConstraintMap, type PackMemberRegistrySource, PackMemberRegistrySourceSchema, packMemberRegistrySource, packMemberVersionRange, type PackSpec, PackSpecSchema, type PerAgentType, type PublishOptions, PublishOptionsSchema, type WorkspaceCapabilityType, decodeExtensionNameSync, extensionTypeFromPlural, extensionTypeLabels, extensionTypePluralLabels, extensionTypePluralSegments, extensionTypePluralSentenceLabels, extensionTypeSentenceLabels, extensionTypeToPlural, extensionTypes, extensionSourceFamilies, extensionTypesInstallableFrom, isInstallableFrom, isExtensionType, isExtensionTypePlural, nonPackExtensionTypePluralSegments, parseExtensionFqnParts, parseExtensionSpecParts, toAuthor, toExtensionType, toExtensionTypePlural, } from "./common.js";
6
+ export { AgentIdSchema, type Author, AuthorSchema, CONTAINER_EXTENSION_TYPES, CommonManifestBaseFields, type ConfigurableAgentId, ConfigurableAgentIdSchema, type ContainerType, EXTENSION_NAME_PATTERN, INSTALLABLE_FROM_BY_TYPE, type ExtensionDependencyConstraintMap, ExtensionDependencyConstraintMapSchema, type ExtensionFqn, type ExtensionFqnParts, ExtensionFqnPartsSchema, ExtensionFqnSchema, type ExtensionName, ExtensionNameSchema, type ExtensionSpec, ExtensionSpecSchema, type ExtensionSourceFamily, type ExtensionType, type ExtensionTypePlural, ExtensionTypePluralSchema, ExtensionTypeSchema, type ExtensionVisibility, ExtensionVisibilitySchema, FQN_PATTERN, LicenseSchema, NON_PACK_FQN_PATTERN, type NonPackExtensionDependencyConstraintMap, NonPackExtensionDependencyConstraintMapSchema, type NonPackExtensionFqn, NonPackExtensionFqnSchema, type NonPackExtensionTypePlural, NonPackManifestFields, PACK_FQN_PATTERN, PER_AGENT_EXTENSION_TYPES, type PackFqn, PackFqnSchema, type PackMemberConstraint, PackMemberConstraintMapSchema, PackMemberConstraintSchema, type PackMemberConstraintMap, type PackMemberRegistrySource, PackMemberRegistrySourceSchema, packMemberRegistrySource, packMemberVersionRange, type PackSpec, PackSpecSchema, type PerAgentType, type PublishOptions, PublishOptionsSchema, type WorkspaceCapabilityType, decodeExtensionNameSync, extensionTypeFromPlural, extensionTypeLabels, extensionTypePluralLabels, extensionTypePluralSegments, extensionTypePluralSentenceLabels, extensionTypeSentenceLabels, extensionTypeToPlural, extensionTypes, extensionSourceFamilies, extensionTypesInstallableFrom, isInstallableFrom, isExtensionType, isExtensionTypePlural, nonPackExtensionTypePluralSegments, parseExtensionFqnParts, parseExtensionSpecParts, splitExtensionReference, type SplitExtensionReference, toAuthor, toExtensionType, toExtensionTypePlural, } from "./common.js";
7
7
  export { type ReleaseAgeExcludePattern, ReleaseAgeExcludePatternSchema, matchesReleaseAgeExcludePattern, } from "./fqn-pattern.js";
8
8
  export { FqnInvalidError, formatFqn, parseFqn, parseFqnOrThrow } from "./fqn.js";
9
9
  export { HANDLE_PATTERN, HANDLE_PATTERN_SOURCE, type Handle, HandleSchema, SLUG_PATTERN, SLUG_PATTERN_SOURCE, type Slug, SlugSchema, decodeHandleSync, decodeSlugSync, handleFromSlug, normalizeHandle, normalizeSlug, slugFromHandle, } from "./handle.js";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @experimental This API is unstable and may change without notice.
5
5
  */
6
- export { AgentIdSchema, AuthorSchema, CONTAINER_EXTENSION_TYPES, CommonManifestBaseFields, ConfigurableAgentIdSchema, EXTENSION_NAME_PATTERN, INSTALLABLE_FROM_BY_TYPE, ExtensionDependencyConstraintMapSchema, ExtensionFqnPartsSchema, ExtensionFqnSchema, ExtensionNameSchema, ExtensionSpecSchema, ExtensionTypePluralSchema, ExtensionTypeSchema, ExtensionVisibilitySchema, FQN_PATTERN, LicenseSchema, NON_PACK_FQN_PATTERN, NonPackExtensionDependencyConstraintMapSchema, NonPackExtensionFqnSchema, NonPackManifestFields, PACK_FQN_PATTERN, PER_AGENT_EXTENSION_TYPES, PackFqnSchema, PackMemberConstraintMapSchema, PackMemberConstraintSchema, PackMemberRegistrySourceSchema, packMemberRegistrySource, packMemberVersionRange, PackSpecSchema, PublishOptionsSchema, decodeExtensionNameSync, extensionTypeFromPlural, extensionTypeLabels, extensionTypePluralLabels, extensionTypePluralSegments, extensionTypePluralSentenceLabels, extensionTypeSentenceLabels, extensionTypeToPlural, extensionTypes, extensionSourceFamilies, extensionTypesInstallableFrom, isInstallableFrom, isExtensionType, isExtensionTypePlural, nonPackExtensionTypePluralSegments, parseExtensionFqnParts, parseExtensionSpecParts, toAuthor, toExtensionType, toExtensionTypePlural, } from "./common.js";
6
+ export { AgentIdSchema, AuthorSchema, CONTAINER_EXTENSION_TYPES, CommonManifestBaseFields, ConfigurableAgentIdSchema, EXTENSION_NAME_PATTERN, INSTALLABLE_FROM_BY_TYPE, ExtensionDependencyConstraintMapSchema, ExtensionFqnPartsSchema, ExtensionFqnSchema, ExtensionNameSchema, ExtensionSpecSchema, ExtensionTypePluralSchema, ExtensionTypeSchema, ExtensionVisibilitySchema, FQN_PATTERN, LicenseSchema, NON_PACK_FQN_PATTERN, NonPackExtensionDependencyConstraintMapSchema, NonPackExtensionFqnSchema, NonPackManifestFields, PACK_FQN_PATTERN, PER_AGENT_EXTENSION_TYPES, PackFqnSchema, PackMemberConstraintMapSchema, PackMemberConstraintSchema, PackMemberRegistrySourceSchema, packMemberRegistrySource, packMemberVersionRange, PackSpecSchema, PublishOptionsSchema, decodeExtensionNameSync, extensionTypeFromPlural, extensionTypeLabels, extensionTypePluralLabels, extensionTypePluralSegments, extensionTypePluralSentenceLabels, extensionTypeSentenceLabels, extensionTypeToPlural, extensionTypes, extensionSourceFamilies, extensionTypesInstallableFrom, isInstallableFrom, isExtensionType, isExtensionTypePlural, nonPackExtensionTypePluralSegments, parseExtensionFqnParts, parseExtensionSpecParts, splitExtensionReference, toAuthor, toExtensionType, toExtensionTypePlural, } from "./common.js";
7
7
  export { ReleaseAgeExcludePatternSchema, matchesReleaseAgeExcludePattern, } from "./fqn-pattern.js";
8
8
  export { FqnInvalidError, formatFqn, parseFqn, parseFqnOrThrow } from "./fqn.js";
9
9
  export { HANDLE_PATTERN, HANDLE_PATTERN_SOURCE, HandleSchema, SLUG_PATTERN, SLUG_PATTERN_SOURCE, SlugSchema, decodeHandleSync, decodeSlugSync, handleFromSlug, normalizeHandle, normalizeSlug, slugFromHandle, } from "./handle.js";
@@ -8,6 +8,7 @@
8
8
  * @experimental This API is unstable and may change without notice.
9
9
  * @packageDocumentation
10
10
  */
11
+ import type { ExtensionName } from "../common.js";
11
12
  import type { SkillExtensionRef } from "./skill.js";
12
13
  import type { McpServerExtensionRef } from "./mcp-server.js";
13
14
  import type { SubagentExtensionRef } from "./subagent.js";
@@ -17,4 +18,12 @@ import type { KnowledgeExtensionRef } from "./knowledge.js";
17
18
  import type { PackRef } from "./pack.js";
18
19
  /** @experimental */
19
20
  export type ExtensionRef = SkillExtensionRef | McpServerExtensionRef | SubagentExtensionRef | RuleExtensionRef | HookExtensionRef | KnowledgeExtensionRef | PackRef;
21
+ /**
22
+ * The name an extension's own manifest gives it: the configured workspace
23
+ * name it occupies. A Registry ref's `name` is the package the Registry
24
+ * serves it under and may differ; Registry operations use that one.
25
+ *
26
+ * @experimental
27
+ */
28
+ export declare const extensionRefName: (ref: ExtensionRef) => ExtensionName;
20
29
  //# sourceMappingURL=extension-ref.d.ts.map
@@ -8,5 +8,29 @@
8
8
  * @experimental This API is unstable and may change without notice.
9
9
  * @packageDocumentation
10
10
  */
11
- export {};
11
+ /**
12
+ * The name an extension's own manifest gives it: the configured workspace
13
+ * name it occupies. A Registry ref's `name` is the package the Registry
14
+ * serves it under and may differ; Registry operations use that one.
15
+ *
16
+ * @experimental
17
+ */
18
+ export const extensionRefName = (ref) => {
19
+ switch (ref.type) {
20
+ case "skill":
21
+ return ref.skill.name;
22
+ case "mcp-server":
23
+ return ref.server.name;
24
+ case "pack":
25
+ return ref.pack.name;
26
+ case "subagent":
27
+ return ref.subagent.name;
28
+ case "rule":
29
+ return ref.rule.name;
30
+ case "hook":
31
+ return ref.hook.name;
32
+ case "knowledge":
33
+ return ref.knowledge.name;
34
+ }
35
+ };
12
36
  //# sourceMappingURL=extension-ref.js.map
@@ -1,3 +1,4 @@
1
+ import * as Option from "effect/Option";
1
2
  import * as Schema from "effect/Schema";
2
3
  export declare const RegistrySourcePatternPartsSchema: Schema.Struct<{
3
4
  readonly owner: Schema.brand<Schema.String, "Handle">;
@@ -6,8 +7,14 @@ export declare const RegistrySourcePatternPartsSchema: Schema.Struct<{
6
7
  readonly versionRange: Schema.optional<Schema.brand<Schema.NonEmptyString, "VersionRange">>;
7
8
  }>;
8
9
  export type RegistrySourcePatternParts = Schema.Schema.Type<typeof RegistrySourcePatternPartsSchema>;
10
+ /**
11
+ * A Registry locator with the configured source it names, when it names one.
12
+ * An unqualified `@owner/...` locator names no source here: which configured
13
+ * Registry it binds to is a workspace decision, made beside the settings that
14
+ * hold the effective default Registry.
15
+ */
9
16
  export type SourceQualifiedRegistrySourcePatternParts = RegistrySourcePatternParts & {
10
- readonly sourceName: string;
17
+ readonly sourceName: Option.Option<string>;
11
18
  };
12
19
  export declare const RegistrySourceRefPartsSchema: Schema.Struct<{
13
20
  readonly owner: Schema.brand<Schema.String, "Handle">;
@@ -17,7 +24,10 @@ export declare const RegistrySourceRefPartsSchema: Schema.Struct<{
17
24
  }>;
18
25
  export type RegistrySourceRefParts = Schema.Schema.Type<typeof RegistrySourceRefPartsSchema>;
19
26
  export declare const parseRegistrySourcePatternParts: (input: string) => RegistrySourcePatternParts | undefined;
20
- /** Parse a Registry locator, assigning unqualified input to the built-in agentxm source. */
27
+ /**
28
+ * Parse a Registry locator, keeping the configured source name it spells
29
+ * (`<source>:@owner/...`) and leaving an unqualified locator unbound.
30
+ */
21
31
  export declare const parseSourceQualifiedRegistrySourcePatternParts: (input: string) => SourceQualifiedRegistrySourcePatternParts | undefined;
22
32
  export declare const parseRegistrySourceRef: (input: string) => RegistrySourceRefParts | undefined;
23
33
  export declare const formatRegistrySourcePatternParts: (value: RegistrySourcePatternParts) => string;
@@ -1,9 +1,10 @@
1
1
  import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
2
3
  import * as Result from "effect/Result";
3
4
  import * as Schema from "effect/Schema";
4
5
  import * as SchemaIssue from "effect/SchemaIssue";
5
6
  import * as SchemaTransformation from "effect/SchemaTransformation";
6
- import { ExtensionNameSchema, ExtensionTypePluralSchema } from "./common.js";
7
+ import { ExtensionNameSchema, ExtensionTypePluralSchema, splitExtensionReference, } from "./common.js";
7
8
  import { HandleSchema } from "./handle.js";
8
9
  import { VersionRangeSchema } from "../version-constraints/version-constraints.js";
9
10
  const invalidRegistrySourcePattern = (input) => `Expected registry source pattern in @handle, @handle/<plural-type>, or @handle/<plural-type>/<name>@<constraint> form, got: ${input}`;
@@ -44,26 +45,12 @@ export const RegistrySourceRefPartsSchema = Schema.Struct({
44
45
  });
45
46
  const decodeRegistrySourcePatternParts = Schema.decodeUnknownResult(RegistrySourcePatternPartsSchema);
46
47
  const decodeRegistrySourceRefParts = Schema.decodeUnknownResult(RegistrySourceRefPartsSchema);
47
- const parseNameAndConstraintSegment = (segment) => {
48
- const atIndex = segment.indexOf("@");
49
- if (atIndex === 0) {
50
- return undefined;
51
- }
52
- if (atIndex === -1) {
53
- return { name: segment };
54
- }
55
- const name = segment.slice(0, atIndex);
56
- const versionRange = segment.slice(atIndex + 1);
57
- if (name.length === 0 || versionRange.length === 0) {
58
- return undefined;
59
- }
60
- return { name, versionRange };
61
- };
62
48
  export const parseRegistrySourcePatternParts = (input) => {
63
49
  if (!input.startsWith("@")) {
64
50
  return undefined;
65
51
  }
66
- const segments = input.split("/");
52
+ const { name: reference, constraint } = splitExtensionReference(input);
53
+ const segments = reference.split("/");
67
54
  if (segments.length < 1 || segments.length > 3) {
68
55
  return undefined;
69
56
  }
@@ -83,17 +70,9 @@ export const parseRegistrySourcePatternParts = (input) => {
83
70
  }
84
71
  else {
85
72
  const type = segments[1];
86
- const third = segments[2];
87
- if (type !== undefined && third !== undefined) {
88
- const parsedName = parseNameAndConstraintSegment(third);
89
- if (parsedName !== undefined) {
90
- candidate = {
91
- owner,
92
- type,
93
- name: parsedName.name,
94
- versionRange: parsedName.versionRange,
95
- };
96
- }
73
+ const name = segments[2];
74
+ if (type !== undefined && name !== undefined) {
75
+ candidate = { owner, type, name, versionRange: constraint };
97
76
  }
98
77
  }
99
78
  if (candidate === undefined) {
@@ -102,25 +81,31 @@ export const parseRegistrySourcePatternParts = (input) => {
102
81
  const result = decodeRegistrySourcePatternParts(candidate);
103
82
  return Result.isSuccess(result) ? result.success : undefined;
104
83
  };
105
- /** Parse a Registry locator, assigning unqualified input to the built-in agentxm source. */
84
+ /**
85
+ * Parse a Registry locator, keeping the configured source name it spells
86
+ * (`<source>:@owner/...`) and leaving an unqualified locator unbound.
87
+ */
106
88
  export const parseSourceQualifiedRegistrySourcePatternParts = (input) => {
107
89
  const unqualified = parseRegistrySourcePatternParts(input);
108
90
  if (unqualified !== undefined) {
109
- return { ...unqualified, sourceName: "agentxm" };
91
+ return { ...unqualified, sourceName: Option.none() };
110
92
  }
111
93
  const separator = input.indexOf(":");
112
94
  if (separator <= 0)
113
95
  return undefined;
114
96
  const sourceName = input.slice(0, separator);
115
97
  const qualified = parseRegistrySourcePatternParts(input.slice(separator + 1));
116
- return qualified === undefined ? undefined : { ...qualified, sourceName };
98
+ return qualified === undefined
99
+ ? undefined
100
+ : { ...qualified, sourceName: Option.some(sourceName) };
117
101
  };
118
102
  export const parseRegistrySourceRef = (input) => {
119
103
  const parsed = parseSourceQualifiedRegistrySourcePatternParts(input);
120
104
  if (parsed?.type === undefined || parsed.name === undefined) {
121
105
  return undefined;
122
106
  }
123
- const result = decodeRegistrySourceRefParts(parsed);
107
+ const { sourceName: _sourceName, ...parts } = parsed;
108
+ const result = decodeRegistrySourceRefParts(parts);
124
109
  return Result.isSuccess(result) ? result.success : undefined;
125
110
  };
126
111
  export const formatRegistrySourcePatternParts = (value) => {
@@ -17,10 +17,14 @@ type NameInput = {
17
17
  readonly pattern: "name-input";
18
18
  readonly name: string;
19
19
  };
20
- /** A namespaced registry source: `[source-name:]@owner/<plural-type>/name`. */
20
+ /**
21
+ * A namespaced registry source: `[source-name:]@owner/<plural-type>/name`.
22
+ * `sourceName` is the configured source the input spells; an unqualified
23
+ * input leaves it unbound for the workspace to assign.
24
+ */
21
25
  type RegistryPatternInput = {
22
26
  readonly pattern: "registry-pattern-input";
23
- readonly sourceName: string;
27
+ readonly sourceName: Option.Option<string>;
24
28
  readonly type: Option.Option<ExtensionTypePlural>;
25
29
  readonly owner: Handle;
26
30
  readonly name: Option.Option<ExtensionName>;
@@ -7,7 +7,6 @@
7
7
  * @experimental This API is unstable and may change without notice.
8
8
  * @packageDocumentation
9
9
  */
10
- import type * as Duration from "effect/Duration";
11
10
  import type * as Effect from "effect/Effect";
12
11
  import type * as Option from "effect/Option";
13
12
  import type { ExtensionType, Handle } from "../extensions/index.js";
@@ -29,11 +28,6 @@ export interface FindOptions {
29
28
  /** Registry owner filter (e.g. "@acme"). */
30
29
  readonly owner: Option.Option<Handle>;
31
30
  readonly versionRange: Option.Option<string>;
32
- /**
33
- * Optional minimum age a registry release must have before it is selectable.
34
- * Omitted for explicit attended installs.
35
- */
36
- readonly minimumReleaseAge?: Option.Option<Duration.Duration>;
37
31
  }
38
32
  export interface NamedRegistryFindOptions {
39
33
  readonly name: string;
@@ -54,6 +48,8 @@ export type NamedRegistryResolution = {
54
48
  readonly refType: "registry";
55
49
  }>;
56
50
  readonly newerHeld?: ReleaseAgeEvidence;
51
+ /** The newest release a range could select, whatever range was requested. */
52
+ readonly newestVisible?: string;
57
53
  } | {
58
54
  readonly kind: "exempted";
59
55
  readonly target: string;
@@ -62,6 +58,7 @@ export type NamedRegistryResolution = {
62
58
  }>;
63
59
  readonly bypassed: ReleaseAgeEvidence;
64
60
  readonly exemption: ReleaseAgeExemption;
61
+ readonly newestVisible?: string;
65
62
  } | {
66
63
  readonly kind: "not_found";
67
64
  readonly target: string;
@@ -87,11 +84,18 @@ export type NamedRegistryVersionDecision = {
87
84
  readonly kind: "selected";
88
85
  readonly version: string;
89
86
  readonly newerHeld?: ReleaseAgeEvidence;
87
+ /**
88
+ * The newest release the index lists that a range could select — not
89
+ * yanked, whatever range was requested — so a caller can say what its
90
+ * constraint held the selection below.
91
+ */
92
+ readonly newestVisible?: string;
90
93
  } | {
91
94
  readonly kind: "exempted";
92
95
  readonly version: string;
93
96
  readonly bypassed: ReleaseAgeEvidence;
94
97
  readonly exemption: ReleaseAgeExemption;
98
+ readonly newestVisible?: string;
95
99
  } | {
96
100
  readonly kind: "not_found";
97
101
  } | {
@@ -39,12 +39,9 @@ export declare const decodeVersionSync: (input: unknown, options?: import("effec
39
39
  */
40
40
  export declare const decodeVersionRangeSync: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => string & import("effect/Brand").Brand<"VersionRange">;
41
41
  /**
42
- * Extract a version range suffix from a source string.
43
- *
44
- * Handles both namespaced (`@handle/name@^1.0.0`) and non-namespaced (`name@^1.0.0`) names.
45
- * Returns `Option.none()` when no version suffix is present.
42
+ * Decode a value as a semver version range, or none when it is not one.
46
43
  */
47
- export declare const parseVersionRange: (sourceString: string) => Option.Option<VersionRange>;
44
+ export declare const decodeVersionRangeOption: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Option.Option<string & import("effect/Brand").Brand<"VersionRange">>;
48
45
  /**
49
46
  * Check whether a string is a valid semver version range.
50
47
  */
@@ -57,15 +54,16 @@ export declare const intersectVersionConstraints: (constraints: ReadonlyArray<st
57
54
  */
58
55
  export declare const hasMinorOrMajorVersionBump: (previousVersion: string, currentVersion: string) => boolean;
59
56
  /**
60
- * Check whether a version satisfies a semver version range.
57
+ * Whether a version is one the range admits: the one predicate every
58
+ * selection and every satisfaction check applies, so a range admits the same
59
+ * versions wherever it is asked. It follows semver exactly, so `*` and an
60
+ * absent range admit every stable version and no prerelease; a prerelease is
61
+ * admitted only by a range that names its version tuple.
61
62
  */
62
63
  export declare const versionSatisfiesRange: (version: Version, range: VersionRange) => boolean;
63
64
  /**
64
- * Select the maximum version that satisfies the range, independent of input
65
- * order.
66
- *
67
- * - `Option.none()` range or `"*"` matches any version.
68
- * - Invalid ranges match nothing.
65
+ * Select the highest version the range admits, independent of input order.
66
+ * An absent range admits what `*` admits; an invalid range admits nothing.
69
67
  */
70
68
  export declare const resolveVersionInRange: <T extends VersionEntryLike>(versions: ReadonlyArray<T>, range: Option.Option<string>) => Option.Option<T>;
71
69
  //# sourceMappingURL=version-constraints.d.ts.map
@@ -46,36 +46,9 @@ export const decodeVersionSync = Schema.decodeUnknownSync(VersionSchema);
46
46
  export const decodeVersionRangeSync = Schema.decodeUnknownSync(VersionRangeSchema);
47
47
  const parseSemverVersion = (version) => semver.parse(version);
48
48
  /**
49
- * Extract a version range suffix from a source string.
50
- *
51
- * Handles both namespaced (`@handle/name@^1.0.0`) and non-namespaced (`name@^1.0.0`) names.
52
- * Returns `Option.none()` when no version suffix is present.
49
+ * Decode a value as a semver version range, or none when it is not one.
53
50
  */
54
- export const parseVersionRange = (sourceString) => {
55
- const decodeRange = (value) => {
56
- try {
57
- return Option.some(decodeVersionRangeSync(value));
58
- }
59
- catch {
60
- return Option.none();
61
- }
62
- };
63
- // For namespaced packages (@handle/name@range), find the @ after the handle
64
- if (sourceString.startsWith("@")) {
65
- const slashIndex = sourceString.indexOf("/");
66
- if (slashIndex === -1)
67
- return Option.none();
68
- const afterHandle = sourceString.indexOf("@", slashIndex + 1);
69
- if (afterHandle === -1)
70
- return Option.none();
71
- return decodeRange(sourceString.slice(afterHandle + 1));
72
- }
73
- // For non-namespaced packages (name@range)
74
- const atIndex = sourceString.indexOf("@");
75
- if (atIndex === -1)
76
- return Option.none();
77
- return decodeRange(sourceString.slice(atIndex + 1));
78
- };
51
+ export const decodeVersionRangeOption = Schema.decodeUnknownOption(VersionRangeSchema);
79
52
  /**
80
53
  * Check whether a string is a valid semver version range.
81
54
  */
@@ -159,29 +132,27 @@ export const hasMinorOrMajorVersionBump = (previousVersion, currentVersion) => {
159
132
  return current.major > previous.major || current.minor > previous.minor;
160
133
  };
161
134
  /**
162
- * Check whether a version satisfies a semver version range.
135
+ * Whether a version is one the range admits: the one predicate every
136
+ * selection and every satisfaction check applies, so a range admits the same
137
+ * versions wherever it is asked. It follows semver exactly, so `*` and an
138
+ * absent range admit every stable version and no prerelease; a prerelease is
139
+ * admitted only by a range that names its version tuple.
163
140
  */
164
141
  export const versionSatisfiesRange = (version, range) => semver.satisfies(version, range);
142
+ /** The range an absent constraint stands for: every stable version. */
143
+ const UNCONSTRAINED_RANGE = "*";
165
144
  /**
166
- * Select the maximum version that satisfies the range, independent of input
167
- * order.
168
- *
169
- * - `Option.none()` range or `"*"` matches any version.
170
- * - Invalid ranges match nothing.
145
+ * Select the highest version the range admits, independent of input order.
146
+ * An absent range admits what `*` admits; an invalid range admits nothing.
171
147
  */
172
148
  export const resolveVersionInRange = (versions, range) => {
173
- const rangeStr = Option.getOrElse(range, () => "*");
174
- // Wildcard means no range filtering
175
- const isWildcard = rangeStr === "*";
176
- // Validate the range early
177
- if (!isWildcard && !isValidVersionRange(rangeStr)) {
149
+ const decoded = decodeVersionRangeOption(Option.getOrElse(range, () => UNCONSTRAINED_RANGE));
150
+ if (Option.isNone(decoded))
178
151
  return Option.none();
179
- }
180
152
  let selected;
181
153
  for (const version of versions) {
182
- if (!isWildcard && !semver.satisfies(version.version, rangeStr)) {
154
+ if (!versionSatisfiesRange(version.version, decoded.value))
183
155
  continue;
184
- }
185
156
  if (selected === undefined || semver.compareBuild(version.version, selected.version) > 0) {
186
157
  selected = version;
187
158
  }
package/package.json CHANGED
@@ -11,14 +11,14 @@
11
11
  },
12
12
  "description": "Shared AgentXM extension model: identities, manifests, version constraints, and agent capabilities. Unstable and unsupported — use the axm.sh CLI.",
13
13
  "devDependencies": {
14
- "@agentxm/specification-metadata": "0.34.0",
14
+ "@agentxm/specification-metadata": "0.35.0",
15
15
  "@effect/vitest": "4.0.0-rc.117",
16
16
  "@fast-check/vitest": "^0.5.0",
17
17
  "@types/semver": "^7.7.1",
18
18
  "@types/spdx-expression-parse": "4.0.0",
19
19
  "@typescript/native": "npm:typescript@^7.0.2",
20
20
  "typescript": "npm:@typescript/typescript6@^6.0.2",
21
- "vitest": "^5.0.0"
21
+ "vitest": "^5.0.1"
22
22
  },
23
23
  "engines": {
24
24
  "node": ">=24.19.0"
@@ -305,5 +305,5 @@
305
305
  },
306
306
  "sideEffects": false,
307
307
  "type": "module",
308
- "version": "0.34.0"
308
+ "version": "0.35.0"
309
309
  }