@pratikpsl/agent-skills 0.3.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/README.md +16 -8
- package/dist/bin/agent-skills.d.ts +3 -0
- package/dist/bin/agent-skills.d.ts.map +1 -0
- package/dist/bin/agent-skills.js +6 -0
- package/dist/bin/agent-skills.js.map +1 -0
- package/dist/cli/commands/add.d.ts +3 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +71 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/dotnet-setup.d.ts +14 -0
- package/dist/cli/commands/dotnet-setup.d.ts.map +1 -0
- package/dist/cli/commands/dotnet-setup.js +110 -0
- package/dist/cli/commands/dotnet-setup.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +36 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +3 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +37 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/copy-skills.d.ts +28 -0
- package/dist/core/copy-skills.d.ts.map +1 -0
- package/dist/core/copy-skills.js +60 -0
- package/dist/core/copy-skills.js.map +1 -0
- package/dist/core/load-pack.d.ts +15 -0
- package/dist/core/load-pack.d.ts.map +1 -0
- package/dist/core/load-pack.js +35 -0
- package/dist/core/load-pack.js.map +1 -0
- package/dist/core/manifest.d.ts +29 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +75 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/resolve-pack.d.ts +7 -0
- package/dist/core/resolve-pack.d.ts.map +1 -0
- package/dist/core/resolve-pack.js +38 -0
- package/dist/core/resolve-pack.js.map +1 -0
- package/package.json +8 -5
- package/templates/dotnet/AgentSkills/entry-points/AGENTS.md +50 -0
- package/templates/dotnet/AgentSkills/entry-points/CLAUDE.md +50 -0
- package/templates/dotnet/AgentSkills/entry-points/antigravity-instructions.md +50 -0
- package/templates/dotnet/AgentSkills/entry-points/copilot-instructions.md +50 -0
- package/templates/dotnet/AgentSkills/entry-points/cursor-instructions.md +50 -0
- package/templates/dotnet/AgentSkills/memory/index.md +22 -0
- package/templates/dotnet/AgentSkills/memory/lessons/design.md +3 -0
- package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/infra.md +1 -0
- package/{src/templates → templates}/dotnet/manifest.json +8 -2
- package/bin/agent-skills.js +0 -7
- package/src/__tests__/copySkills.test.js +0 -161
- package/src/__tests__/list.test.js +0 -49
- package/src/__tests__/manifest.test.js +0 -72
- package/src/commands/add.js +0 -89
- package/src/commands/dotnet-setup.js +0 -67
- package/src/commands/init.js +0 -42
- package/src/commands/list.js +0 -41
- package/src/index.js +0 -33
- package/src/lib/copySkills.js +0 -84
- package/src/lib/manifest.js +0 -117
- package/src/lib/resolvePack.js +0 -44
- package/src/templates/dotnet/AgentSkills/entry-points/AGENTS.md +0 -16
- package/src/templates/dotnet/AgentSkills/entry-points/CLAUDE.md +0 -16
- package/src/templates/dotnet/AgentSkills/entry-points/copilot-instructions.md +0 -16
- package/src/templates/dotnet/AgentSkills/entry-points/cursor-instructions.md +0 -16
- package/src/templates/dotnet/AgentSkills/memory/index.md +0 -22
- package/src/templates/dotnet/AgentSkills/memory/lessons/design.md +0 -3
- /package/{src/templates → templates}/dotnet/AgentSkills/OPERATING.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/README.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/agents/README.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/agents/architect.agent.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/agents/developer.agent.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/api.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/auth.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/csharp.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/db.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/mcp.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/lessons/testing.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/memory/schema.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/INDEX.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/README.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/code-standards/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/core/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/csharp-xunit/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/design/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/dotnet-api/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/dotnet-best-practices/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/harness/SKILL.md +0 -0
- /package/{src/templates → templates}/dotnet/AgentSkills/skills/mcp_dotnet/SKILL.md +0 -0
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// src/__tests__/list.test.js
|
|
2
|
-
// Integration-style test: verifies that list output matches manifest contents.
|
|
3
|
-
// We don't spawn the CLI process — instead we call the underlying lib functions
|
|
4
|
-
// that the list command uses, which is the behaviour that matters.
|
|
5
|
-
|
|
6
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
-
import { mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import os from 'os';
|
|
10
|
-
import { readManifest } from '../lib/manifest.js';
|
|
11
|
-
|
|
12
|
-
function makeTempDir() {
|
|
13
|
-
const dir = path.join(os.tmpdir(), `agent-skills-list-test-${Date.now()}`);
|
|
14
|
-
mkdirSync(dir, { recursive: true });
|
|
15
|
-
return dir;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('list — manifest content matches output data', () => {
|
|
19
|
-
let tmpDir;
|
|
20
|
-
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
tmpDir = makeTempDir();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('returns all skills declared in manifest', () => {
|
|
30
|
-
const manifest = {
|
|
31
|
-
name: '@pratikpsl/agent-skills-dotnet',
|
|
32
|
-
version: '0.1.0',
|
|
33
|
-
skills: [
|
|
34
|
-
{ name: 'core', description: 'Core principles', path: 'AgentSkills/skills/core' },
|
|
35
|
-
{ name: 'design', description: 'Design principles', path: 'AgentSkills/skills/design' },
|
|
36
|
-
{ name: 'dotnet-api', description: '.NET API rules', path: 'AgentSkills/skills/dotnet-api' },
|
|
37
|
-
],
|
|
38
|
-
};
|
|
39
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), JSON.stringify(manifest));
|
|
40
|
-
|
|
41
|
-
const result = readManifest(tmpDir);
|
|
42
|
-
|
|
43
|
-
// The list command renders result.skills — verify the data is identical.
|
|
44
|
-
expect(result.skills.map((s) => s.name)).toEqual(['core', 'design', 'dotnet-api']);
|
|
45
|
-
expect(result.skills.every((s) => typeof s.description === 'string')).toBe(true);
|
|
46
|
-
expect(result.name).toBe(manifest.name);
|
|
47
|
-
expect(result.version).toBe(manifest.version);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// src/__tests__/manifest.test.js
|
|
2
|
-
// Unit tests for the manifest reader/validator.
|
|
3
|
-
|
|
4
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
5
|
-
import { mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import os from 'os';
|
|
8
|
-
import { readManifest } from '../lib/manifest.js';
|
|
9
|
-
|
|
10
|
-
function makeTempDir() {
|
|
11
|
-
const dir = path.join(os.tmpdir(), `agent-skills-test-${Date.now()}`);
|
|
12
|
-
mkdirSync(dir, { recursive: true });
|
|
13
|
-
return dir;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
describe('readManifest', () => {
|
|
17
|
-
let tmpDir;
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
tmpDir = makeTempDir();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('parses a valid manifest', () => {
|
|
28
|
-
const manifest = {
|
|
29
|
-
name: '@pratikpsl/agent-skills-dotnet',
|
|
30
|
-
version: '0.1.0',
|
|
31
|
-
skills: [
|
|
32
|
-
{ name: 'core', description: 'Core principles', path: 'AgentSkills/skills/core' },
|
|
33
|
-
],
|
|
34
|
-
};
|
|
35
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), JSON.stringify(manifest));
|
|
36
|
-
const result = readManifest(tmpDir);
|
|
37
|
-
expect(result.name).toBe('@pratikpsl/agent-skills-dotnet');
|
|
38
|
-
expect(result.skills).toHaveLength(1);
|
|
39
|
-
expect(result.skills[0].name).toBe('core');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('throws when manifest.json is missing', () => {
|
|
43
|
-
expect(() => readManifest(tmpDir)).toThrowError(/manifest.json not found/);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('throws when manifest.json is not valid JSON', () => {
|
|
47
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), 'not json!');
|
|
48
|
-
expect(() => readManifest(tmpDir)).toThrowError(/not valid JSON/);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('throws when "name" field is missing', () => {
|
|
52
|
-
const bad = { version: '0.1.0', skills: [] };
|
|
53
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), JSON.stringify(bad));
|
|
54
|
-
expect(() => readManifest(tmpDir)).toThrowError(/missing required field "name"/);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('throws when "skills" is not an array', () => {
|
|
58
|
-
const bad = { name: 'test', version: '0.1.0', skills: 'not-an-array' };
|
|
59
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), JSON.stringify(bad));
|
|
60
|
-
expect(() => readManifest(tmpDir)).toThrowError(/"skills" must be an array/);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('throws when a skill entry is missing the "path" field', () => {
|
|
64
|
-
const bad = {
|
|
65
|
-
name: 'test',
|
|
66
|
-
version: '0.1.0',
|
|
67
|
-
skills: [{ name: 'core', description: 'desc' }],
|
|
68
|
-
};
|
|
69
|
-
writeFileSync(path.join(tmpDir, 'manifest.json'), JSON.stringify(bad));
|
|
70
|
-
expect(() => readManifest(tmpDir)).toThrowError(/missing or has an empty "path" field/);
|
|
71
|
-
});
|
|
72
|
-
});
|
package/src/commands/add.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// src/commands/add.js
|
|
2
|
-
// `agent-skills add <pack> <skillName|--all>`
|
|
3
|
-
//
|
|
4
|
-
// Copies a single named skill (or all skills with --all) from a pack into the
|
|
5
|
-
// current project's AgentSkills/ folder.
|
|
6
|
-
//
|
|
7
|
-
// This is the generic command. `dotnet-setup` is a convenience wrapper over this.
|
|
8
|
-
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import { resolvePack } from '../lib/resolvePack.js';
|
|
11
|
-
import { readManifest } from '../lib/manifest.js';
|
|
12
|
-
import { copySkills, ensureAgentSkillsDir } from '../lib/copySkills.js';
|
|
13
|
-
|
|
14
|
-
/** @param {import('commander').Command} program */
|
|
15
|
-
export function addCommand(program) {
|
|
16
|
-
program
|
|
17
|
-
.command('add <pack> [skillName]')
|
|
18
|
-
.description('Copy a skill (or all skills with --all) from a pack into this project')
|
|
19
|
-
.option('--all', 'Copy all skills from the pack', false)
|
|
20
|
-
.option('--force', 'Overwrite existing files', false)
|
|
21
|
-
.option('--path <dir>', 'Target project root (default: cwd)', process.cwd())
|
|
22
|
-
.action(async (pack, skillName, options) => {
|
|
23
|
-
if (!skillName && !options.all) {
|
|
24
|
-
console.error('✗ Specify a skill name or pass --all to copy every skill.');
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const targetDir = path.resolve(options.path);
|
|
29
|
-
|
|
30
|
-
let packDir;
|
|
31
|
-
try {
|
|
32
|
-
packDir = await resolvePack(pack);
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error(`✗ ${err.message}`);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let manifest;
|
|
39
|
-
try {
|
|
40
|
-
manifest = readManifest(packDir);
|
|
41
|
-
} catch (err) {
|
|
42
|
-
console.error(`✗ ${err.message}`);
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let skillsToCopy;
|
|
47
|
-
if (options.all) {
|
|
48
|
-
skillsToCopy = manifest.skills;
|
|
49
|
-
} else {
|
|
50
|
-
const found = manifest.skills.find((s) => s.name === skillName);
|
|
51
|
-
if (!found) {
|
|
52
|
-
const available = manifest.skills.map((s) => s.name).join(', ');
|
|
53
|
-
console.error(`✗ Skill "${skillName}" not found in pack "${pack}".`);
|
|
54
|
-
console.error(` Available: ${available}`);
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
skillsToCopy = [found];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
ensureAgentSkillsDir(targetDir);
|
|
61
|
-
console.log(`\nCopying from ${manifest.name}@${manifest.version} → ${targetDir}\n`);
|
|
62
|
-
|
|
63
|
-
const { written, skipped } = copySkills({
|
|
64
|
-
skills: skillsToCopy,
|
|
65
|
-
packDir,
|
|
66
|
-
targetDir,
|
|
67
|
-
force: options.force,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
printSummary(written, skipped);
|
|
71
|
-
|
|
72
|
-
if (written.length === 0 && skipped.length > 0) {
|
|
73
|
-
// Everything was skipped — treat as a soft warning, not a hard error.
|
|
74
|
-
process.exit(0);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @param {string[]} written
|
|
81
|
-
* @param {string[]} skipped
|
|
82
|
-
*/
|
|
83
|
-
function printSummary(written, skipped) {
|
|
84
|
-
console.log('\n' + '─'.repeat(50));
|
|
85
|
-
console.log(`✔ Done — ${written.length} written, ${skipped.length} skipped.`);
|
|
86
|
-
if (skipped.length > 0) {
|
|
87
|
-
console.log(' (Run with --force to overwrite skipped files.)');
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// src/commands/dotnet-setup.js
|
|
2
|
-
// `agent-skills dotnet-setup`
|
|
3
|
-
//
|
|
4
|
-
// Convenience command equivalent to:
|
|
5
|
-
// agent-skills add @pratikpsl/agent-skills-dotnet --all
|
|
6
|
-
//
|
|
7
|
-
// Rationale: gives first-time users a single, memorable command for the .NET
|
|
8
|
-
// stack without requiring them to know the full pack name.
|
|
9
|
-
|
|
10
|
-
import path from 'path';
|
|
11
|
-
import { resolvePack } from '../lib/resolvePack.js';
|
|
12
|
-
import { readManifest } from '../lib/manifest.js';
|
|
13
|
-
import { copySkills, ensureAgentSkillsDir } from '../lib/copySkills.js';
|
|
14
|
-
|
|
15
|
-
const DOTNET_PACK = '@pratikpsl/agent-skills-dotnet';
|
|
16
|
-
|
|
17
|
-
/** @param {import('commander').Command} program */
|
|
18
|
-
export function dotnetSetupCommand(program) {
|
|
19
|
-
program
|
|
20
|
-
.command('dotnet-setup')
|
|
21
|
-
.description(`Install the full .NET/C# agent skill set (shortcut for: add ${DOTNET_PACK} --all)`)
|
|
22
|
-
.option('--force', 'Overwrite existing files', false)
|
|
23
|
-
.option('--path <dir>', 'Target project root (default: cwd)', process.cwd())
|
|
24
|
-
.action(async (options) => {
|
|
25
|
-
const targetDir = path.resolve(options.path);
|
|
26
|
-
|
|
27
|
-
console.log(`\n🔧 Setting up .NET agent skills in: ${targetDir}\n`);
|
|
28
|
-
|
|
29
|
-
let packDir;
|
|
30
|
-
try {
|
|
31
|
-
packDir = await resolvePack(DOTNET_PACK);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
console.error(`✗ ${err.message}`);
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let manifest;
|
|
38
|
-
try {
|
|
39
|
-
manifest = readManifest(packDir);
|
|
40
|
-
} catch (err) {
|
|
41
|
-
console.error(`✗ ${err.message}`);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
ensureAgentSkillsDir(targetDir);
|
|
46
|
-
console.log(`Copying from ${manifest.name}@${manifest.version}\n`);
|
|
47
|
-
|
|
48
|
-
const { written, skipped } = copySkills({
|
|
49
|
-
skills: manifest.skills,
|
|
50
|
-
packDir,
|
|
51
|
-
targetDir,
|
|
52
|
-
force: options.force,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
console.log('\n' + '─'.repeat(50));
|
|
56
|
-
console.log(`✔ .NET skills installed — ${written.length} written, ${skipped.length} skipped.`);
|
|
57
|
-
|
|
58
|
-
if (skipped.length > 0) {
|
|
59
|
-
console.log(' (Run with --force to overwrite skipped files.)');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (written.length === 0 && skipped.length === 0) {
|
|
63
|
-
console.error('\n✗ No skills were copied. Check that the pack contains skill entries.');
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
package/src/commands/init.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// src/commands/init.js
|
|
2
|
-
// `agent-skills init`
|
|
3
|
-
//
|
|
4
|
-
// Scaffolds an empty AgentSkills/ folder + index.json in the current project
|
|
5
|
-
// if one doesn't exist yet. Safe to run multiple times (idempotent).
|
|
6
|
-
|
|
7
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
|
|
10
|
-
/** @param {import('commander').Command} program */
|
|
11
|
-
export function initCommand(program) {
|
|
12
|
-
program
|
|
13
|
-
.command('init')
|
|
14
|
-
.description('Scaffold an empty AgentSkills/ folder in the current project')
|
|
15
|
-
.option('--path <dir>', 'Target project root (default: cwd)', process.cwd())
|
|
16
|
-
.option('--force', 'Overwrite existing files', false)
|
|
17
|
-
.action(async (options) => {
|
|
18
|
-
const targetDir = path.resolve(options.path);
|
|
19
|
-
const agentSkillsDir = path.join(targetDir, 'AgentSkills');
|
|
20
|
-
|
|
21
|
-
if (existsSync(agentSkillsDir) && !options.force) {
|
|
22
|
-
console.log(`AgentSkills/ already exists at ${agentSkillsDir}`);
|
|
23
|
-
console.log('Use --force to reinitialize.');
|
|
24
|
-
process.exit(0);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
mkdirSync(agentSkillsDir, { recursive: true });
|
|
28
|
-
console.log(`✓ Created ${agentSkillsDir}`);
|
|
29
|
-
|
|
30
|
-
const indexPath = path.join(agentSkillsDir, 'index.json');
|
|
31
|
-
if (!existsSync(indexPath) || options.force) {
|
|
32
|
-
const indexContent = {
|
|
33
|
-
skills: [],
|
|
34
|
-
_comment: 'Add skills via `agent-skills add <pack> <skillName>` or `agent-skills dotnet-setup`',
|
|
35
|
-
};
|
|
36
|
-
writeFileSync(indexPath, JSON.stringify(indexContent, null, 2) + '\n', 'utf8');
|
|
37
|
-
console.log(`✓ Created ${indexPath}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.log('\n✔ AgentSkills initialized. Run `agent-skills dotnet-setup` to add .NET skills.');
|
|
41
|
-
});
|
|
42
|
-
}
|
package/src/commands/list.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// src/commands/list.js
|
|
2
|
-
// `agent-skills list [pack]`
|
|
3
|
-
//
|
|
4
|
-
// Lists available skills in an installed or available pack.
|
|
5
|
-
// When no pack is specified, lists all packs the CLI knows about.
|
|
6
|
-
|
|
7
|
-
import { resolvePack } from '../lib/resolvePack.js';
|
|
8
|
-
import { readManifest } from '../lib/manifest.js';
|
|
9
|
-
|
|
10
|
-
/** @param {import('commander').Command} program */
|
|
11
|
-
export function listCommand(program) {
|
|
12
|
-
program
|
|
13
|
-
.command('list [pack]')
|
|
14
|
-
.description('List available skills in a pack (default: all known packs)')
|
|
15
|
-
.action(async (pack) => {
|
|
16
|
-
const packsToList = pack
|
|
17
|
-
? [pack]
|
|
18
|
-
: ['dotnet']; // Extend this array as new packs are added.
|
|
19
|
-
|
|
20
|
-
let exitCode = 0;
|
|
21
|
-
|
|
22
|
-
for (const packName of packsToList) {
|
|
23
|
-
try {
|
|
24
|
-
const packDir = await resolvePack(packName);
|
|
25
|
-
const manifest = readManifest(packDir);
|
|
26
|
-
|
|
27
|
-
console.log(`\n📦 ${manifest.name}@${manifest.version}`);
|
|
28
|
-
console.log('─'.repeat(50));
|
|
29
|
-
|
|
30
|
-
for (const skill of manifest.skills) {
|
|
31
|
-
console.log(` • ${skill.name.padEnd(28)} ${skill.description}`);
|
|
32
|
-
}
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error(`\n✗ Could not list pack "${packName}": ${err.message}`);
|
|
35
|
-
exitCode = 1;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (exitCode !== 0) process.exit(exitCode);
|
|
40
|
-
});
|
|
41
|
-
}
|
package/src/index.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// src/index.js
|
|
2
|
-
// Wires up the root `commander` program and registers all sub-commands.
|
|
3
|
-
// This file is the only place that imports commander; sub-commands receive
|
|
4
|
-
// the program instance so they stay independently testable.
|
|
5
|
-
|
|
6
|
-
import { Command } from 'commander';
|
|
7
|
-
import { createRequire } from 'module';
|
|
8
|
-
import { initCommand } from './commands/init.js';
|
|
9
|
-
import { listCommand } from './commands/list.js';
|
|
10
|
-
import { addCommand } from './commands/add.js';
|
|
11
|
-
import { dotnetSetupCommand } from './commands/dotnet-setup.js';
|
|
12
|
-
|
|
13
|
-
// Read version from our own package.json without a JSON import assertion
|
|
14
|
-
// (works in Node 18 without the --experimental-json-modules flag).
|
|
15
|
-
const require = createRequire(import.meta.url);
|
|
16
|
-
const { version } = require('../package.json');
|
|
17
|
-
|
|
18
|
-
const program = new Command();
|
|
19
|
-
|
|
20
|
-
program
|
|
21
|
-
.name('agent-skills')
|
|
22
|
-
.description('Scaffold and manage AI agent skills across projects')
|
|
23
|
-
.version(version);
|
|
24
|
-
|
|
25
|
-
initCommand(program);
|
|
26
|
-
listCommand(program);
|
|
27
|
-
addCommand(program);
|
|
28
|
-
dotnetSetupCommand(program);
|
|
29
|
-
|
|
30
|
-
program.parseAsync(process.argv).catch((err) => {
|
|
31
|
-
console.error(`\n✗ ${err.message}`);
|
|
32
|
-
process.exit(1);
|
|
33
|
-
});
|
package/src/lib/copySkills.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// src/lib/copySkills.js
|
|
2
|
-
// Copies skill files from a pack into the target project's AgentSkills/ folder.
|
|
3
|
-
//
|
|
4
|
-
// Rules enforced here:
|
|
5
|
-
// - Never overwrite an existing file without --force; warn and skip instead.
|
|
6
|
-
// - Directories are created recursively as needed.
|
|
7
|
-
// - Returns a summary object for the caller to print: { written, skipped }.
|
|
8
|
-
//
|
|
9
|
-
// This module contains no pack-specific logic. The manifest tells it what to copy;
|
|
10
|
-
// it does not inspect SKILL.md contents.
|
|
11
|
-
|
|
12
|
-
import { cpSync, existsSync, mkdirSync, rmSync } from 'fs';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {Object} CopyResult
|
|
17
|
-
* @property {string[]} written Files that were successfully written.
|
|
18
|
-
* @property {string[]} skipped Files that were skipped because they already exist.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Copies a list of skill source directories into the target project.
|
|
23
|
-
*
|
|
24
|
-
* @param {object} options
|
|
25
|
-
* @param {import('./manifest.js').SkillEntry[]} options.skills
|
|
26
|
-
* Skills to copy, filtered from the manifest (all or a single skill).
|
|
27
|
-
* @param {string} options.packDir Absolute path to the pack root.
|
|
28
|
-
* @param {string} options.targetDir Absolute path to the target project root.
|
|
29
|
-
* @param {boolean} options.force When true, overwrite existing files.
|
|
30
|
-
* @returns {CopyResult}
|
|
31
|
-
*/
|
|
32
|
-
export function copySkills({ skills, packDir, targetDir, force }) {
|
|
33
|
-
/** @type {string[]} */
|
|
34
|
-
const written = [];
|
|
35
|
-
/** @type {string[]} */
|
|
36
|
-
const skipped = [];
|
|
37
|
-
|
|
38
|
-
for (const skill of skills) {
|
|
39
|
-
const src = path.join(packDir, skill.path);
|
|
40
|
-
// dest overrides where the file lands in the target project.
|
|
41
|
-
// Used for IDE entry-points (e.g. CLAUDE.md, .github/copilot-instructions.md)
|
|
42
|
-
// that must live outside AgentSkills/ at a specific root-relative path.
|
|
43
|
-
const destRelPath = skill.dest ?? skill.path;
|
|
44
|
-
const dest = path.join(targetDir, destRelPath);
|
|
45
|
-
|
|
46
|
-
if (!existsSync(src)) {
|
|
47
|
-
console.warn(` ⚠ Source path for skill "${skill.name}" not found: ${src}`);
|
|
48
|
-
skipped.push(destRelPath);
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (existsSync(dest) && !force) {
|
|
53
|
-
console.warn(
|
|
54
|
-
` ⚠ Skipping "${skill.name}" — destination already exists. Use --force to overwrite.`
|
|
55
|
-
);
|
|
56
|
-
skipped.push(destRelPath);
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
mkdirSync(path.dirname(dest), { recursive: true });
|
|
61
|
-
// Remove the destination first when forcing — cpSync throws "src and dest cannot
|
|
62
|
-
// be the same" on Windows if the dest directory already exists, even with force:true.
|
|
63
|
-
if (force && existsSync(dest)) {
|
|
64
|
-
rmSync(dest, { recursive: true, force: true });
|
|
65
|
-
}
|
|
66
|
-
cpSync(src, dest, { recursive: true });
|
|
67
|
-
written.push(destRelPath);
|
|
68
|
-
console.log(` ✓ ${destRelPath}`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return { written, skipped };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Ensures the AgentSkills root directory exists in the target project.
|
|
76
|
-
*
|
|
77
|
-
* @param {string} targetDir Absolute path to the target project root.
|
|
78
|
-
* @returns {string} Absolute path to AgentSkills/.
|
|
79
|
-
*/
|
|
80
|
-
export function ensureAgentSkillsDir(targetDir) {
|
|
81
|
-
const dir = path.join(targetDir, 'AgentSkills');
|
|
82
|
-
mkdirSync(dir, { recursive: true });
|
|
83
|
-
return dir;
|
|
84
|
-
}
|
package/src/lib/manifest.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// src/lib/manifest.js
|
|
2
|
-
// Reads and validates a pack's manifest.json.
|
|
3
|
-
//
|
|
4
|
-
// The manifest is the contract between a skills pack and the CLI.
|
|
5
|
-
// It declares what skills exist, where their source files are, and where
|
|
6
|
-
// they should be placed in the target project.
|
|
7
|
-
//
|
|
8
|
-
// Expected shape:
|
|
9
|
-
// {
|
|
10
|
-
// "name": "@pratikpsl/agent-skills-dotnet",
|
|
11
|
-
// "version": "0.1.0",
|
|
12
|
-
// "skills": [
|
|
13
|
-
// {
|
|
14
|
-
// "name": "core",
|
|
15
|
-
// "description": "...",
|
|
16
|
-
// "path": "AgentSkills/skills/core" // relative to pack root
|
|
17
|
-
// }
|
|
18
|
-
// ]
|
|
19
|
-
// }
|
|
20
|
-
|
|
21
|
-
import { readFileSync, existsSync } from 'fs';
|
|
22
|
-
import path from 'path';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Object} SkillEntry
|
|
26
|
-
* @property {string} name Short identifier used as a CLI argument.
|
|
27
|
-
* @property {string} description Human-readable purpose of the skill.
|
|
28
|
-
* @property {string} path Source path of the skill, relative to the pack root.
|
|
29
|
-
* @property {string} [dest] Destination path in the target project, relative to the
|
|
30
|
-
* project root. When absent, `path` is used as the destination.
|
|
31
|
-
* Use this for IDE entry-point files that must land outside
|
|
32
|
-
* AgentSkills/ (e.g. CLAUDE.md, .github/copilot-instructions.md).
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @typedef {Object} Manifest
|
|
37
|
-
* @property {string} name Package name.
|
|
38
|
-
* @property {string} version Semver string.
|
|
39
|
-
* @property {SkillEntry[]} skills All skills provided by this pack.
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Reads and validates the manifest.json for a pack.
|
|
44
|
-
*
|
|
45
|
-
* @param {string} packDir Absolute path to the pack root.
|
|
46
|
-
* @returns {Manifest}
|
|
47
|
-
* @throws {Error} When manifest is missing, unreadable, or structurally invalid.
|
|
48
|
-
*/
|
|
49
|
-
export function readManifest(packDir) {
|
|
50
|
-
const manifestPath = path.join(packDir, 'manifest.json');
|
|
51
|
-
|
|
52
|
-
if (!existsSync(manifestPath)) {
|
|
53
|
-
throw new Error(
|
|
54
|
-
`manifest.json not found in pack at "${packDir}". ` +
|
|
55
|
-
`This pack may be malformed or out of date.`
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let raw;
|
|
60
|
-
try {
|
|
61
|
-
raw = readFileSync(manifestPath, 'utf8');
|
|
62
|
-
if (raw.charCodeAt(0) === 0xFEFF) {
|
|
63
|
-
raw = raw.slice(1);
|
|
64
|
-
}
|
|
65
|
-
} catch (err) {
|
|
66
|
-
throw new Error(`Could not read manifest.json: ${err.message}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let manifest;
|
|
70
|
-
try {
|
|
71
|
-
manifest = JSON.parse(raw);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
throw new Error(`manifest.json at "${manifestPath}" is not valid JSON: ${err.message}`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
validateManifest(manifest, manifestPath);
|
|
77
|
-
return manifest;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Throws with a descriptive message if the manifest does not meet the required shape.
|
|
82
|
-
*
|
|
83
|
-
* @param {unknown} manifest
|
|
84
|
-
* @param {string} filePath Used only in error messages.
|
|
85
|
-
*/
|
|
86
|
-
function validateManifest(manifest, filePath) {
|
|
87
|
-
if (typeof manifest !== 'object' || manifest === null) {
|
|
88
|
-
throw new Error(`manifest.json at "${filePath}" must be a JSON object.`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const required = ['name', 'version', 'skills'];
|
|
92
|
-
for (const key of required) {
|
|
93
|
-
if (!(key in manifest)) {
|
|
94
|
-
throw new Error(`manifest.json is missing required field "${key}".`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!Array.isArray(manifest.skills)) {
|
|
99
|
-
throw new Error(`manifest.json "skills" must be an array.`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (const [i, skill] of manifest.skills.entries()) {
|
|
103
|
-
for (const field of ['name', 'description', 'path']) {
|
|
104
|
-
if (typeof skill[field] !== 'string' || !skill[field].trim()) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`manifest.json skills[${i}] is missing or has an empty "${field}" field.`
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// dest is optional; when present it must be a non-empty string.
|
|
111
|
-
if ('dest' in skill && (typeof skill.dest !== 'string' || !skill.dest.trim())) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
`manifest.json skills[${i}] has an invalid "dest" field — must be a non-empty string when present.`
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
package/src/lib/resolvePack.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// src/lib/resolvePack.js
|
|
2
|
-
// Locates a templates folder bundled inside the package itself.
|
|
3
|
-
// Since everything is now in one package, we don't need to fetch
|
|
4
|
-
// anything from npm registry at runtime.
|
|
5
|
-
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
import { existsSync } from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = path.dirname(__filename);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Canonical package names for built-in packs.
|
|
15
|
-
* @type {Record<string, string>}
|
|
16
|
-
*/
|
|
17
|
-
const PACK_ALIASES = {
|
|
18
|
-
dotnet: 'dotnet',
|
|
19
|
-
'skills-dotnet': 'dotnet',
|
|
20
|
-
'@pratikpsl/agent-skills-dotnet': 'dotnet',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Resolves a pack name or alias to its installed directory.
|
|
25
|
-
*
|
|
26
|
-
* @param {string} packName Short alias (e.g. "dotnet") or full package name.
|
|
27
|
-
* @returns {Promise<string>} Absolute path to the pack root.
|
|
28
|
-
* @throws {Error} When the pack cannot be located.
|
|
29
|
-
*/
|
|
30
|
-
export async function resolvePack(packName) {
|
|
31
|
-
const normalized = PACK_ALIASES[packName] ?? packName.replace(/^@pratikpsl\/agent-skills-/, '').replace(/^skills-/, '');
|
|
32
|
-
|
|
33
|
-
// Locate the templates folder inside the package src directory
|
|
34
|
-
const templateDir = path.resolve(__dirname, '..', 'templates', normalized);
|
|
35
|
-
|
|
36
|
-
if (existsSync(templateDir) && existsSync(path.join(templateDir, 'manifest.json'))) {
|
|
37
|
-
return templateDir;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
throw new Error(
|
|
41
|
-
`Pack "${packName}" (mapped to "${normalized}") is not bundled with this version of the CLI. ` +
|
|
42
|
-
`Currently available packs: dotnet`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Codex / OpenAI Entry Point
|
|
2
|
-
|
|
3
|
-
This file is a lightweight entry point for Codex and OpenAI agents.
|
|
4
|
-
|
|
5
|
-
`AgentSkills/` is the single source of truth for skills, agents, memory,
|
|
6
|
-
prerequisites, checklists, and project rules used by all coding agents and
|
|
7
|
-
AI-enabled IDEs in this repository.
|
|
8
|
-
|
|
9
|
-
## Start Here
|
|
10
|
-
|
|
11
|
-
1. Read `AgentSkills/OPERATING.md`.
|
|
12
|
-
2. Follow skill routing in `AgentSkills/skills/INDEX.md`.
|
|
13
|
-
3. Load role definitions from `AgentSkills/agents/` only when the task requires them.
|
|
14
|
-
|
|
15
|
-
Do not duplicate canonical instructions in this file. Edit shared guidance in
|
|
16
|
-
`AgentSkills/`.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Claude Entry Point
|
|
2
|
-
|
|
3
|
-
This file is a lightweight entry point for Claude (Anthropic).
|
|
4
|
-
|
|
5
|
-
`AgentSkills/` is the single source of truth for skills, agents, memory,
|
|
6
|
-
prerequisites, checklists, and project rules used by all coding agents and
|
|
7
|
-
AI-enabled IDEs in this repository.
|
|
8
|
-
|
|
9
|
-
## Start Here
|
|
10
|
-
|
|
11
|
-
1. Read `AgentSkills/OPERATING.md`.
|
|
12
|
-
2. Follow skill routing in `AgentSkills/skills/INDEX.md`.
|
|
13
|
-
3. Load role definitions from `AgentSkills/agents/` only when the task requires them.
|
|
14
|
-
|
|
15
|
-
Do not duplicate canonical instructions in this file. Edit shared guidance in
|
|
16
|
-
`AgentSkills/`.
|