xdrs-core 0.49.0 → 0.49.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.
@@ -75,7 +75,7 @@ Examples:
75
75
 
76
76
  **Skill naming**
77
77
 
78
- Unlike Policies, Research, Articles, and Initiatives, skill packages MUST NOT use a numeric prefix. A skill is identified by a descriptive name alone, keeping it compatible with the wider agentskills ecosystem, where clients (including this framework's own agentskills-format consumers) expect a plain descriptive identifier rather than a sequence number. Each skill name MUST be unique within its `scope/type/subject/skills/` namespace; check for an existing skill with the same name before creating a new one.
78
+ Unlike Policies, Research, Articles, and Initiatives, skill packages are not auto-numbered. A skill is identified by a descriptive name, keeping it compatible with the wider agentskills ecosystem, where clients (including this framework's own agentskills-format consumers) expect a plain descriptive identifier rather than an auto-generated sequence number. The name MAY still contain digits, including as a prefix, when that is simply part of the descriptive name (e.g., `2fa-setup`). Each skill name MUST be unique within its `scope/type/subject/skills/` namespace; check for an existing skill with the same name before creating a new one.
79
79
 
80
80
  **SKILL.md format** (agentskills spec)
81
81
 
@@ -111,7 +111,7 @@ Known gotchas and how to handle them.
111
111
 
112
112
  Rules:
113
113
  - The `name` field MUST match the folder name exactly (e.g., `code-review`). This keeps skill identifiers simple and aligned with the filesystem hierarchy.
114
- - The directory name and the `name:` field MUST contain only lowercase alphanumeric characters and hyphens (e.g., `code-review`), with no numeric prefix.
114
+ - The directory name and the `name:` field MUST contain only lowercase alphanumeric characters and hyphens (e.g., `code-review`, `2fa-setup`).
115
115
  - `## Overview` SHOULD state the task objective, expected outcome, and relevant prerequisites or tools when they matter.
116
116
  - `## Instructions` SHOULD include verification steps or acceptance criteria at the end of the task, or at the end of major phases when partial validation matters.
117
117
  - For diagram format preferences and non-Markdown asset rules, see [`_core-adr-policy-020`](020-media-and-asset-standards.md).
package/lib/lint.js CHANGED
@@ -19,7 +19,8 @@ const ALLOWED_SUBJECTS = {
19
19
  const TYPE_NAMES = new Set(Object.keys(TYPE_TO_ID));
20
20
  const RESERVED_SCOPES = new Set(['_core', '_local']);
21
21
  const NUMBERED_FILE_RE = /^(\d{3,})-([a-z0-9-]+)\.md$/;
22
- // Skill package folders are not numbered (see _core-adr-policy-003): plain lowercase kebab-case.
22
+ // Skill package folders are not auto-numbered (see _core-adr-policy-003): plain lowercase
23
+ // kebab-case; digits are allowed anywhere in the name, including as a prefix.
23
24
  const SKILL_DIR_RE = /^[a-z0-9-]+$/;
24
25
  const REQUIRED_ROOT_INDEX_TEXT = 'XDRS scopes listed last override the ones listed first';
25
26
  const SUBJECT_ARTIFACT_DIRS = new Set(['skills', 'articles', 'researches', 'initiatives']);
package/lib/lint.test.js CHANGED
@@ -53,9 +53,9 @@ test('reports broken local document links in skill files', () => {
53
53
  const workspaceRoot = createWorkspace('broken-skill-link', {
54
54
  '.xdrs/index.md': rootIndex(),
55
55
  '.xdrs/_local/adrs/index.md': localAdrIndex([
56
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check local links'
56
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check local links'
57
57
  ]),
58
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': skillDocument('See [Missing](missing.md).'),
58
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillDocument('See [Missing](missing.md).'),
59
59
  });
60
60
 
61
61
  const result = lintWorkspace(workspaceRoot);
@@ -300,11 +300,11 @@ test('reports unknown frontmatter fields in SKILL.md files', () => {
300
300
  const workspaceRoot = createWorkspace('skill-unknown-frontmatter', {
301
301
  '.xdrs/index.md': rootIndex(),
302
302
  '.xdrs/_local/adrs/index.md': localAdrIndex([
303
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
303
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
304
304
  ]),
305
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': [
305
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': [
306
306
  '---',
307
- 'name: 001-check-links',
307
+ 'name: check-links',
308
308
  'description: Test skill document',
309
309
  'unknown-field: some value',
310
310
  '---',
@@ -329,11 +329,11 @@ test('accepts all known frontmatter fields in SKILL.md files', () => {
329
329
  const workspaceRoot = createWorkspace('skill-known-frontmatter', {
330
330
  '.xdrs/index.md': rootIndex(),
331
331
  '.xdrs/_local/adrs/index.md': localAdrIndex([
332
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
332
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
333
333
  ]),
334
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': [
334
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': [
335
335
  '---',
336
- 'name: 001-check-links',
336
+ 'name: check-links',
337
337
  'description: Test skill document',
338
338
  'license: MIT',
339
339
  'metadata:',
@@ -358,6 +358,34 @@ test('accepts all known frontmatter fields in SKILL.md files', () => {
358
358
  expect(result.errors.join('\n')).not.toContain('unknown field');
359
359
  });
360
360
 
361
+ test('accepts skill package names containing digits, including as a prefix', () => {
362
+ const workspaceRoot = createWorkspace('skill-name-with-digits', {
363
+ '.xdrs/index.md': rootIndex(),
364
+ '.xdrs/_local/adrs/index.md': localAdrIndex([
365
+ '- [2fa-setup](principles/skills/2fa-setup/SKILL.md) - 2FA setup'
366
+ ]),
367
+ '.xdrs/_local/adrs/principles/skills/2fa-setup/SKILL.md': [
368
+ '---',
369
+ 'name: 2fa-setup',
370
+ 'description: Test skill document',
371
+ '---',
372
+ '',
373
+ '## Overview',
374
+ '',
375
+ 'Test skill overview.',
376
+ '',
377
+ '## Instructions',
378
+ '',
379
+ 'Test instructions.',
380
+ ''
381
+ ].join('\n'),
382
+ });
383
+
384
+ const result = lintWorkspace(workspaceRoot);
385
+
386
+ expect(result.errors.join('\n')).not.toContain('Invalid skill package name');
387
+ });
388
+
361
389
  test('derives expected frontmatter name from the markdown heading title', () => {
362
390
  const workspaceRoot = createWorkspace('heading-name-match', {
363
391
  '.xdrs/index.md': rootIndex(),
@@ -2063,10 +2091,10 @@ test('reports unexpected directories inside a skill package', () => {
2063
2091
  '.xdrs/index.md': rootIndex(),
2064
2092
  '.xdrs/_local/index.md': localScopeIndex(),
2065
2093
  '.xdrs/_local/adrs/index.md': localAdrIndex([
2066
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check local links'
2094
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check local links'
2067
2095
  ]),
2068
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': skillDocument('Skill body.'),
2069
- '.xdrs/_local/adrs/principles/skills/001-check-links/extras/note.txt': 'unexpected',
2096
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillDocument('Skill body.'),
2097
+ '.xdrs/_local/adrs/principles/skills/check-links/extras/note.txt': 'unexpected',
2070
2098
  });
2071
2099
 
2072
2100
  const result = lintWorkspace(workspaceRoot);
@@ -3181,7 +3209,7 @@ function xdrDocument(body) {
3181
3209
  function skillDocument(body) {
3182
3210
  return [
3183
3211
  '---',
3184
- 'name: 001-check-links',
3212
+ 'name: check-links',
3185
3213
  'description: Test skill document',
3186
3214
  '---',
3187
3215
  '',
@@ -3302,9 +3330,9 @@ test('reports emoji in SKILL.md', () => {
3302
3330
  const workspaceRoot = createWorkspace('skill-emoji', {
3303
3331
  '.xdrs/index.md': rootIndex(),
3304
3332
  '.xdrs/_local/adrs/index.md': localAdrIndex([
3305
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
3333
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
3306
3334
  ]),
3307
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': skillDocument('Step 1: do something \u2705'),
3335
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillDocument('Step 1: do something \u2705'),
3308
3336
  });
3309
3337
 
3310
3338
  const result = lintWorkspace(workspaceRoot);
@@ -3585,13 +3613,13 @@ test('reports XDRS element frontmatter description exceeding 1024 characters', (
3585
3613
  });
3586
3614
 
3587
3615
  test('reports SKILL.md frontmatter name exceeding 64 characters', () => {
3588
- const longName = '001-check-links-' + 'a'.repeat(50);
3616
+ const longName = 'check-links-' + 'a'.repeat(60);
3589
3617
  const workspaceRoot = createWorkspace('skill-name-too-long', {
3590
3618
  '.xdrs/index.md': rootIndex(),
3591
3619
  '.xdrs/_local/adrs/index.md': localAdrIndex([
3592
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
3620
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
3593
3621
  ]),
3594
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': [
3622
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': [
3595
3623
  '---',
3596
3624
  `name: ${longName}`,
3597
3625
  'description: Test skill document',
@@ -3617,11 +3645,11 @@ test('reports SKILL.md frontmatter description exceeding 1024 characters', () =>
3617
3645
  const workspaceRoot = createWorkspace('skill-description-too-long', {
3618
3646
  '.xdrs/index.md': rootIndex(),
3619
3647
  '.xdrs/_local/adrs/index.md': localAdrIndex([
3620
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
3648
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
3621
3649
  ]),
3622
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': [
3650
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': [
3623
3651
  '---',
3624
- 'name: 001-check-links',
3652
+ 'name: check-links',
3625
3653
  `description: ${'x'.repeat(1025)}`,
3626
3654
  '---',
3627
3655
  '',
@@ -3693,9 +3721,9 @@ test('reports SKILL.md exceeding 6500 word limit', () => {
3693
3721
  const workspaceRoot = createWorkspace('skill-too-many-words', {
3694
3722
  '.xdrs/index.md': rootIndex(),
3695
3723
  '.xdrs/_local/adrs/index.md': localAdrIndex([
3696
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
3724
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
3697
3725
  ]),
3698
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': skillDocument(longBody),
3726
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillDocument(longBody),
3699
3727
  });
3700
3728
 
3701
3729
  const result = lintWorkspace(workspaceRoot);
@@ -3709,11 +3737,11 @@ test('passes when extra files exist at skill package root', () => {
3709
3737
  const workspaceRoot = createWorkspace('extra-skill-file', {
3710
3738
  '.xdrs/index.md': rootIndex(),
3711
3739
  '.xdrs/_local/adrs/index.md': localAdrIndex([
3712
- '- [001-check-links](principles/skills/001-check-links/SKILL.md) - Check links'
3740
+ '- [check-links](principles/skills/check-links/SKILL.md) - Check links'
3713
3741
  ]),
3714
- '.xdrs/_local/adrs/principles/skills/001-check-links/SKILL.md': skillDocument('Body.'),
3715
- '.xdrs/_local/adrs/principles/skills/001-check-links/extra.md': 'Allowed extra file',
3716
- '.xdrs/_local/adrs/principles/skills/001-check-links/schema.json': '{"type":"object"}',
3742
+ '.xdrs/_local/adrs/principles/skills/check-links/SKILL.md': skillDocument('Body.'),
3743
+ '.xdrs/_local/adrs/principles/skills/check-links/extra.md': 'Allowed extra file',
3744
+ '.xdrs/_local/adrs/principles/skills/check-links/schema.json': '{"type":"object"}',
3717
3745
  });
3718
3746
 
3719
3747
  const result = lintWorkspace(workspaceRoot);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xdrs-core",
3
- "version": "0.49.0",
3
+ "version": "0.49.1",
4
4
  "description": "XDRS (eXtensible Decision Record System): a framework to structure, compile and distribute Architectural (ADR), Business (BDR), and Engineering (EDR) decision records contents so that AI agents and humans can reliably find and use them with hierarchical scopes and controlled rollout in the format of distributable versioned packages.",
5
5
  "repository": {
6
6
  "type": "git",