@agentxm/extension-content 0.42.0 → 0.42.1

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.
@@ -38,12 +38,18 @@ export interface ExtractedSkillMetadata {
38
38
  readonly frontmatter?: Readonly<Record<string, unknown>>;
39
39
  }
40
40
  /**
41
- * Read external metadata without applying AXM's authoring contract. The source
41
+ * Read descriptive metadata without imposing a conformance gate. The source
42
42
  * remains authoritative: unknown fields, display names and metadata values are
43
43
  * retained as declared. Missing or malformed metadata does not make an explicit
44
44
  * SKILL.md path unavailable to acquisition.
45
45
  */
46
46
  export declare const extractSkillMetadata: (content: string) => ExtractedSkillMetadata;
47
+ /**
48
+ * Choose a native directory component without changing the skill declaration.
49
+ * The fallback is the caller's already validated source/package identity, never
50
+ * the physical content directory (which may be named src in an AXM envelope).
51
+ */
52
+ export declare const skillDirectoryName: (declaredName: string | undefined, fallback: string) => string;
47
53
  /** Validate parsed YAML against the pinned Agent Skills metadata contract. */
48
54
  export declare const validateSkillFrontmatter: (input: unknown, expectedDirectoryName?: string) => SkillFrontmatterValidation;
49
55
  /**
@@ -50,7 +50,7 @@ export const SkillFrontmatterSchema = Schema.Struct({
50
50
  const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
51
51
  const allowedFrontmatterFields = new Set(AGENT_SKILLS_FRONTMATTER_FIELDS);
52
52
  /**
53
- * Read external metadata without applying AXM's authoring contract. The source
53
+ * Read descriptive metadata without imposing a conformance gate. The source
54
54
  * remains authoritative: unknown fields, display names and metadata values are
55
55
  * retained as declared. Missing or malformed metadata does not make an explicit
56
56
  * SKILL.md path unavailable to acquisition.
@@ -73,6 +73,26 @@ export const extractSkillMetadata = (content) => {
73
73
  return {};
74
74
  }
75
75
  };
76
+ /**
77
+ * Choose a native directory component without changing the skill declaration.
78
+ * The fallback is the caller's already validated source/package identity, never
79
+ * the physical content directory (which may be named src in an AXM envelope).
80
+ */
81
+ export const skillDirectoryName = (declaredName, fallback) => {
82
+ const reserved = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu;
83
+ if (declaredName === undefined ||
84
+ declaredName.length === 0 ||
85
+ declaredName.trim() !== declaredName ||
86
+ declaredName === "." ||
87
+ declaredName === ".." ||
88
+ declaredName.endsWith(".") ||
89
+ /[<>:"/\\|?*]/u.test(declaredName) ||
90
+ [...declaredName].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127) ||
91
+ reserved.test(declaredName) ||
92
+ new TextEncoder().encode(declaredName).length > 255)
93
+ return reserved.test(fallback) ? `skill-${fallback}` : fallback;
94
+ return declaredName;
95
+ };
76
96
  /** Validate parsed YAML against the pinned Agent Skills metadata contract. */
77
97
  export const validateSkillFrontmatter = (input, expectedDirectoryName) => {
78
98
  if (!isRecord(input)) {
@@ -12,7 +12,7 @@
12
12
  */
13
13
  export { AGENT_SKILLS_COMPATIBILITY_MAX_LENGTH, AGENT_SKILLS_DESCRIPTION_MAX_LENGTH, AGENT_SKILLS_FRONTMATTER_FIELDS, AGENT_SKILLS_NAME_MAX_LENGTH, AGENT_SKILLS_REFERENCE_VALIDATOR_URL, AGENT_SKILLS_SPECIFICATION_URL, AGENT_SKILLS_STANDARD_REVISION, } from "./content/agent-skills-standard.js";
14
14
  export { FRONTMATTER_PARSE_FALLBACK_REASON, FrontmatterParseFailure, type FrontmatterResult, parseFrontmatterEffect, parseFrontmatterSync, } from "./content/frontmatter.js";
15
- export { type ExtractedSkillMetadata, type SkillFrontmatter, SkillFrontmatterSchema, type SkillFrontmatterValidation, parseSkillMd, extractSkillMetadata, validateSkillFrontmatter, } from "./content/skill-content.js";
15
+ export { type ExtractedSkillMetadata, type SkillFrontmatter, SkillFrontmatterSchema, type SkillFrontmatterValidation, parseSkillMd, extractSkillMetadata, skillDirectoryName, validateSkillFrontmatter, } from "./content/skill-content.js";
16
16
  export { type Skill } from "./content/skill-types.js";
17
17
  export { type DecodedSubagentPackage, type NativeSubagentContent, type ResolvedSubagentImplementation, type SelectedSubagentImplementation, SubagentContentError, loadSubagentPackage, nativeSubagentFormat, parseNativeSubagent, readSubagentPackage, selectSubagentImplementation, } from "./content/subagent-content.js";
18
18
  export { ArchiveGuardrailError, type ArchiveGuardrailLimits, ZIP_LOCAL_SIGNATURE, type ZipEntry, checkForbiddenSourceEntries, defaultReadEntry, parseZipCentralDirectory, validateArchive, } from "./packaging/archive-guardrails.js";
package/dist/src/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
  export { AGENT_SKILLS_COMPATIBILITY_MAX_LENGTH, AGENT_SKILLS_DESCRIPTION_MAX_LENGTH, AGENT_SKILLS_FRONTMATTER_FIELDS, AGENT_SKILLS_NAME_MAX_LENGTH, AGENT_SKILLS_REFERENCE_VALIDATOR_URL, AGENT_SKILLS_SPECIFICATION_URL, AGENT_SKILLS_STANDARD_REVISION, } from "./content/agent-skills-standard.js";
14
14
  export { FRONTMATTER_PARSE_FALLBACK_REASON, FrontmatterParseFailure, parseFrontmatterEffect, parseFrontmatterSync, } from "./content/frontmatter.js";
15
- export { SkillFrontmatterSchema, parseSkillMd, extractSkillMetadata, validateSkillFrontmatter, } from "./content/skill-content.js";
15
+ export { SkillFrontmatterSchema, parseSkillMd, extractSkillMetadata, skillDirectoryName, validateSkillFrontmatter, } from "./content/skill-content.js";
16
16
  export {} from "./content/skill-types.js";
17
17
  export { SubagentContentError, loadSubagentPackage, nativeSubagentFormat, parseNativeSubagent, readSubagentPackage, selectSubagentImplementation, } from "./content/subagent-content.js";
18
18
  export { ArchiveGuardrailError, ZIP_LOCAL_SIGNATURE, checkForbiddenSourceEntries, defaultReadEntry, parseZipCentralDirectory, validateArchive, } from "./packaging/archive-guardrails.js";
@@ -7,6 +7,7 @@ export declare const hookEnvelopeRules: {
7
7
  manifestSchemaValid: {
8
8
  check: (context: HookRuleContext) => Effect.Effect<readonly import("../../rule.ts").AdvisoryFinding[], never, never>;
9
9
  kind: "advisory";
10
+ enabledByDefault?: false;
10
11
  id: string;
11
12
  description: string;
12
13
  severity: import("../../rule.ts").Severity;
@@ -38,6 +38,7 @@ const UTF8_BOM = "\uFEFF";
38
38
  const decoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
39
39
  export const frontmatterParseableRule = {
40
40
  id: RULE_ID,
41
+ enabledByDefault: false,
41
42
  description: "SKILL.md frontmatter is a valid YAML mapping.",
42
43
  kind: "advisory",
43
44
  severity: "error",
@@ -41,6 +41,7 @@ const finding = (message) => ({
41
41
  });
42
42
  export const frontmatterStandardValidRule = {
43
43
  id: RULE_ID,
44
+ enabledByDefault: false,
44
45
  description: "SKILL.md metadata conforms to the pinned Agent Skills standard.",
45
46
  kind: "advisory",
46
47
  severity: "error",
@@ -25,7 +25,7 @@ export const manifestPresentRule = makeManifestPresentRule({
25
25
  ruleId: RULE_ID,
26
26
  description: "Native skills include a root skill.json manifest.",
27
27
  manifestFile: SKILL_JSON,
28
- missingMessage: "skill.json is missing for this native skill. Create skill.json with the required manifest fields (`owner`, `type`, `name`, `version`).",
28
+ missingMessage: "This AXM skill package is missing its required skill.json manifest. Restore the package manifest before managing it.",
29
29
  getFiles: (context) => context.packageFiles,
30
30
  applies: (context) => context.subject.isNative,
31
31
  });
@@ -39,7 +39,6 @@ import type { SkillFileAccessor, SkillRuleContext } from "../../context.js";
39
39
  * @experimental This API is unstable and may change without notice.
40
40
  */
41
41
  export interface InstalledSkillInfo {
42
- readonly validationPurpose?: "authoring" | "management";
43
42
  readonly isNative: boolean;
44
43
  readonly skillJson: unknown;
45
44
  readonly expectedName?: string;
@@ -44,9 +44,6 @@
44
44
  */
45
45
  export const buildSkillRuleContexts = (input) => input.installedSkills.map((info) => ({
46
46
  subject: {
47
- ...(info.validationPurpose === undefined
48
- ? {}
49
- : { validationPurpose: info.validationPurpose }),
50
47
  isNative: info.isNative,
51
48
  skillJson: info.skillJson,
52
49
  ...(info.expectedName === undefined ? {} : { expectedName: info.expectedName }),
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * `skill/*` rule catalog.
3
3
  *
4
- * Per the lint design, registry publish and `axm lint`
5
- * run exactly these rules against each skill context:
4
+ * Ordinary lint checks management obligations; the two frontmatter
5
+ * conformance rules run only when explicitly configured:
6
6
  *
7
7
  * | ID | Severity | Autofix |
8
8
  * | -------------------------------------- | -------- | ------- |
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * `skill/*` rule catalog.
3
3
  *
4
- * Per the lint design, registry publish and `axm lint`
5
- * run exactly these rules against each skill context:
4
+ * Ordinary lint checks management obligations; the two frontmatter
5
+ * conformance rules run only when explicitly configured:
6
6
  *
7
7
  * | ID | Severity | Autofix |
8
8
  * | -------------------------------------- | -------- | ------- |
@@ -25,7 +25,6 @@
25
25
  * @experimental This API is unstable and may change without notice.
26
26
  * @packageDocumentation
27
27
  */
28
- import * as Effect from "effect/Effect";
29
28
  import { skillMdPresentRule } from "./skill/skill-md-present.js";
30
29
  import { manifestPresentRule } from "./skill/manifest-present.js";
31
30
  import { frontmatterParseableRule } from "./skill/frontmatter-parseable.js";
@@ -34,15 +33,6 @@ import { manifestSchemaValidRule } from "./skill/manifest-schema-valid.js";
34
33
  import { manifestKeysRecognizedRule } from "./skill/manifest-keys-recognized.js";
35
34
  import { recommendedPacksValidRule } from "./skill/recommended-packs-valid.js";
36
35
  import { standaloneDeclarationValidRule } from "./skill/standalone-declaration-valid.js";
37
- /**
38
- * Authoring rules do not run as routine health checks for acquired content.
39
- * Skill presence remains a management obligation; accepted identity, integrity,
40
- * ownership and projection checks are supplied by the workspace catalog.
41
- */
42
- const authoringOnly = (rule) => ({
43
- ...rule,
44
- check: (context) => context.subject.validationPurpose === "management" ? Effect.succeed([]) : rule.check(context),
45
- });
46
36
  /**
47
37
  * Ordered `skill/*` rule catalog. Declaration order is the evaluation
48
38
  * order within a single `evaluateContexts` call (deterministic ordering is
@@ -52,14 +42,12 @@ const authoringOnly = (rule) => ({
52
42
  */
53
43
  export const skillRules = [
54
44
  skillMdPresentRule,
55
- ...[
56
- manifestPresentRule,
57
- frontmatterParseableRule,
58
- frontmatterStandardValidRule,
59
- manifestSchemaValidRule,
60
- manifestKeysRecognizedRule,
61
- standaloneDeclarationValidRule,
62
- recommendedPacksValidRule,
63
- ].map(authoringOnly),
45
+ manifestPresentRule,
46
+ frontmatterParseableRule,
47
+ frontmatterStandardValidRule,
48
+ manifestSchemaValidRule,
49
+ manifestKeysRecognizedRule,
50
+ standaloneDeclarationValidRule,
51
+ recommendedPacksValidRule,
64
52
  ];
65
53
  //# sourceMappingURL=skill.js.map
@@ -19,6 +19,7 @@ export type LintCatalogView = "workspace" | "git-index";
19
19
  export interface LintCatalogRuleMetadata {
20
20
  readonly id: string;
21
21
  readonly defaultSeverity: Severity;
22
+ readonly enabledByDefault?: false;
22
23
  readonly group: LintCatalogGroup;
23
24
  readonly views: ReadonlyArray<LintCatalogView>;
24
25
  }
@@ -34,91 +35,115 @@ export declare const lintCatalogRuleMetadata: readonly ({
34
35
  defaultSeverity: "error";
35
36
  group: "skill";
36
37
  views: readonly ["workspace", "git-index"];
38
+ enabledByDefault?: never;
39
+ } | {
40
+ id: string;
41
+ enabledByDefault: false;
42
+ defaultSeverity: "error";
43
+ group: "skill";
44
+ views: readonly ["workspace", "git-index"];
37
45
  } | {
38
46
  id: string;
39
47
  defaultSeverity: "warning";
40
48
  group: "skill";
41
49
  views: readonly ["workspace", "git-index"];
50
+ enabledByDefault?: never;
42
51
  } | {
43
52
  id: string;
44
53
  defaultSeverity: "error";
45
54
  group: "pack";
46
55
  views: readonly ["workspace", "git-index"];
56
+ enabledByDefault?: never;
47
57
  } | {
48
58
  id: string;
49
59
  defaultSeverity: "error";
50
60
  group: "subagent";
51
61
  views: readonly ["workspace", "git-index"];
62
+ enabledByDefault?: never;
52
63
  } | {
53
64
  id: string;
54
65
  defaultSeverity: "warning";
55
66
  group: "subagent";
56
67
  views: readonly ["workspace", "git-index"];
68
+ enabledByDefault?: never;
57
69
  } | {
58
70
  id: string;
59
71
  defaultSeverity: "error";
60
72
  group: "mcp-server";
61
73
  views: readonly ["workspace", "git-index"];
74
+ enabledByDefault?: never;
62
75
  } | {
63
76
  id: string;
64
77
  defaultSeverity: "warning";
65
78
  group: "mcp-server";
66
79
  views: readonly ["workspace", "git-index"];
80
+ enabledByDefault?: never;
67
81
  } | {
68
82
  id: string;
69
83
  defaultSeverity: "error";
70
84
  group: "hook";
71
85
  views: readonly ["workspace", "git-index"];
86
+ enabledByDefault?: never;
72
87
  } | {
73
88
  id: string;
74
89
  defaultSeverity: "warning";
75
90
  group: "hook";
76
91
  views: readonly ["workspace", "git-index"];
92
+ enabledByDefault?: never;
77
93
  } | {
78
94
  id: string;
79
95
  defaultSeverity: "error";
80
96
  group: "rule";
81
97
  views: readonly ["workspace", "git-index"];
98
+ enabledByDefault?: never;
82
99
  } | {
83
100
  id: string;
84
101
  defaultSeverity: "warning";
85
102
  group: "rule";
86
103
  views: readonly ["workspace", "git-index"];
104
+ enabledByDefault?: never;
87
105
  } | {
88
106
  id: string;
89
107
  defaultSeverity: "error";
90
108
  group: "knowledge";
91
109
  views: readonly ["workspace", "git-index"];
110
+ enabledByDefault?: never;
92
111
  } | {
93
112
  id: string;
94
113
  defaultSeverity: "warning";
95
114
  group: "knowledge";
96
115
  views: readonly ["workspace", "git-index"];
116
+ enabledByDefault?: never;
97
117
  } | {
98
118
  id: string;
99
119
  defaultSeverity: "error";
100
120
  group: "workspace";
101
121
  views: readonly ["workspace", "git-index"];
122
+ enabledByDefault?: never;
102
123
  } | {
103
124
  id: string;
104
125
  defaultSeverity: "info";
105
126
  group: "workspace";
106
127
  views: readonly ["workspace", "git-index"];
128
+ enabledByDefault?: never;
107
129
  } | {
108
130
  id: string;
109
131
  defaultSeverity: "warning";
110
132
  group: "workspace";
111
133
  views: readonly ["workspace"];
134
+ enabledByDefault?: never;
112
135
  } | {
113
136
  id: string;
114
137
  defaultSeverity: "warning";
115
138
  group: "workspace";
116
139
  views: readonly ["workspace", "git-index"];
140
+ enabledByDefault?: never;
117
141
  } | {
118
142
  id: string;
119
143
  defaultSeverity: "error";
120
144
  group: "workspace";
121
145
  views: readonly ["workspace"];
146
+ enabledByDefault?: never;
122
147
  })[];
123
148
  /** Every accepted lint-rule identity, in catalog/reporting order. */
124
149
  export declare const allLintCatalogRuleIds: readonly string[];
@@ -40,9 +40,16 @@ const defineLintCatalog = (entries) => {
40
40
  export const lintCatalogRuleMetadata = defineLintCatalog([
41
41
  { id: "skill/skill-md-present", defaultSeverity: "error", group: "skill", views: bothViews },
42
42
  { id: "skill/manifest-present", defaultSeverity: "error", group: "skill", views: bothViews },
43
- { id: "skill/frontmatter-parseable", defaultSeverity: "error", group: "skill", views: bothViews },
43
+ {
44
+ id: "skill/frontmatter-parseable",
45
+ enabledByDefault: false,
46
+ defaultSeverity: "error",
47
+ group: "skill",
48
+ views: bothViews,
49
+ },
44
50
  {
45
51
  id: "skill/frontmatter-standard-valid",
52
+ enabledByDefault: false,
46
53
  defaultSeverity: "error",
47
54
  group: "skill",
48
55
  views: bothViews,
@@ -68,8 +68,8 @@ export type LintConfig = Schema.Schema.Type<typeof LintConfigSchema>;
68
68
  /**
69
69
  * The platform-canonical `LintConfig` — empty rules, no overrides.
70
70
  *
71
- * Registry publish uses this config; it carries no overrides so every rule
72
- * fires at its catalog severity.
71
+ * It carries no overrides: enabled rules use their catalog severity and
72
+ * opt-in conformance rules remain disabled.
73
73
  *
74
74
  * @experimental This API is unstable and may change without notice.
75
75
  */
@@ -90,8 +90,8 @@ export const LintConfigSchema = Schema.Struct({
90
90
  /**
91
91
  * The platform-canonical `LintConfig` — empty rules, no overrides.
92
92
  *
93
- * Registry publish uses this config; it carries no overrides so every rule
94
- * fires at its catalog severity.
93
+ * It carries no overrides: enabled rules use their catalog severity and
94
+ * opt-in conformance rules remain disabled.
95
95
  *
96
96
  * @experimental This API is unstable and may change without notice.
97
97
  */
@@ -140,7 +140,6 @@ export interface SkillRuleContext<S = SkillContent> {
140
140
  */
141
141
  export interface SkillContent {
142
142
  /** Authored checks are opt-in for acquired content; normal health checks use management. */
143
- readonly validationPurpose?: "authoring" | "management";
144
143
  readonly isNative: boolean;
145
144
  readonly skillJson: unknown;
146
145
  /** Agent-facing skill directory name used for the standard name-match check. */
@@ -57,11 +57,13 @@ const withSeverity = (finding, severity) => ({
57
57
  * @experimental This API is unstable and may change without notice.
58
58
  */
59
59
  export const evaluateContexts = (rules, contexts, config) => Effect.forEach(rules.flatMap((rule) => contexts.map((context) => ({ rule, context }))), ({ rule, context }) => evaluateOne(rule, context, config), { concurrency: 1 });
60
- const evaluateOne = (rule, context, config) => Effect.map(rule.check(context), (rawFindings) => ({
61
- rule,
62
- context,
63
- findings: applySeverityConfig(rule, rawFindings, config),
64
- }));
60
+ const evaluateOne = (rule, context, config) => rule.enabledByDefault === false && config.rules?.[rule.id] === undefined
61
+ ? Effect.succeed({ rule, context, findings: [] })
62
+ : Effect.map(rule.check(context), (rawFindings) => ({
63
+ rule,
64
+ context,
65
+ findings: applySeverityConfig(rule, rawFindings, config),
66
+ }));
65
67
  const applySeverityConfig = (rule, findings, config) => {
66
68
  const override = config.rules?.[rule.id];
67
69
  const effective = resolveEffectiveSeverity(rule.severity, override);
@@ -75,6 +75,8 @@ export type LintFinding = AdvisoryFinding;
75
75
  * @experimental This API is unstable and may change without notice.
76
76
  */
77
77
  export interface RuleBase {
78
+ /** Conformance rules run only when explicitly enabled in lint.rules. */
79
+ readonly enabledByDefault?: false;
78
80
  readonly id: string;
79
81
  readonly description: string;
80
82
  readonly severity: Severity;
@@ -153,7 +153,7 @@ export const resolveManifest = (input) => Effect.gen(function* () {
153
153
  })));
154
154
  yield* Effect.fromResult(validateManifestHasNoAgentsField(manifestEntry.fileName, parsed));
155
155
  const schema = manifestSchemaForType(input.type);
156
- yield* Schema.decodeUnknownEffect(schema)(parsed, input.type === "hook" ? { onExcessProperty: "error" } : undefined).pipe(Effect.mapError((error) => {
156
+ yield* Schema.decodeUnknownEffect(schema)(parsed, input.type === "hook" || input.type === "skill" ? { onExcessProperty: "error" } : undefined).pipe(Effect.mapError((error) => {
157
157
  const companionPackageError = classifyCompanionPackageManifestError(parsed);
158
158
  return new ManifestError({
159
159
  code: companionPackageError?.code ?? "manifest_schema_invalid",
package/package.json CHANGED
@@ -4,14 +4,14 @@
4
4
  "url": "https://github.com/agentxm/axm/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@agentxm/extension-model": "^0.42.0",
7
+ "@agentxm/extension-model": "^0.42.1",
8
8
  "effect": "4.0.1",
9
9
  "smol-toml": "^1.9.0",
10
10
  "yaml": "^2.9.1"
11
11
  },
12
12
  "description": "AXM extension content behavior: skill and subagent content parsing, Knowledge bundle inspection and search, the lint rule catalog, and archive and manifest validation shared by the axm CLI and the AgentXM Registry. Unstable and unsupported — use the axm.sh CLI.",
13
13
  "devDependencies": {
14
- "@agentxm/specification-metadata": "^0.42.0",
14
+ "@agentxm/specification-metadata": "^0.42.1",
15
15
  "@effect/platform-node": "4.0.1",
16
16
  "@effect/vitest": "4.0.1",
17
17
  "@fast-check/vitest": "^0.5.0",
@@ -60,5 +60,5 @@
60
60
  },
61
61
  "sideEffects": false,
62
62
  "type": "module",
63
- "version": "0.42.0"
63
+ "version": "0.42.1"
64
64
  }