@opendirectory.dev/skills 0.1.71 → 0.1.73
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 +19 -0
- package/package.json +6 -1
- package/registry.json +8 -0
- package/skills/domain-expired-opportunity-finder/.env.example +21 -0
- package/skills/domain-expired-opportunity-finder/README.md +198 -0
- package/skills/domain-expired-opportunity-finder/SKILL.md +540 -0
- package/skills/domain-expired-opportunity-finder/evals/evals.json +58 -0
- package/skills/domain-expired-opportunity-finder/references/guardrails.md +125 -0
- package/skills/domain-expired-opportunity-finder/references/output-format.md +200 -0
- package/skills/domain-expired-opportunity-finder/references/risk-flags.md +135 -0
- package/skills/domain-expired-opportunity-finder/references/scoring-model.md +198 -0
- package/.claude/skills/claude-md-generator/.env.example +0 -7
- package/.claude/skills/claude-md-generator/README.md +0 -78
- package/.claude/skills/claude-md-generator/SKILL.md +0 -248
- package/.claude/skills/claude-md-generator/evals/evals.json +0 -35
- package/.claude/skills/claude-md-generator/references/section-guide.md +0 -175
- package/src/e2e.test.ts +0 -38
- package/src/fs-adapters.test.ts +0 -91
- package/src/fs-adapters.ts +0 -65
- package/src/index.ts +0 -179
- package/src/transformers.ts +0 -6
- package/tsconfig.json +0 -8
package/src/fs-adapters.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
|
-
|
|
5
|
-
export function resolvePath(p: string): string {
|
|
6
|
-
if (p.startsWith('~/') || p === '~') {
|
|
7
|
-
return path.resolve(p.replace(/^~/, os.homedir()));
|
|
8
|
-
}
|
|
9
|
-
return path.resolve(p);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function safeWriteFile(filePath: string, content: string): Promise<void> {
|
|
13
|
-
const resolvedPath = resolvePath(filePath);
|
|
14
|
-
const dir = path.dirname(resolvedPath);
|
|
15
|
-
await fs.mkdir(dir, { recursive: true });
|
|
16
|
-
await fs.writeFile(resolvedPath, content, 'utf-8');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function safeAppendFile(filePath: string, content: string): Promise<void> {
|
|
20
|
-
const resolvedPath = resolvePath(filePath);
|
|
21
|
-
const dir = path.dirname(resolvedPath);
|
|
22
|
-
await fs.mkdir(dir, { recursive: true });
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const existingContent = await fs.readFile(resolvedPath, 'utf-8');
|
|
26
|
-
if (existingContent.includes(content)) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const prefix = existingContent.length > 0 && !existingContent.endsWith('\n') ? '\n' : '';
|
|
31
|
-
await fs.appendFile(resolvedPath, prefix + content, 'utf-8');
|
|
32
|
-
} catch (error: any) {
|
|
33
|
-
if (error.code === 'ENOENT') {
|
|
34
|
-
await fs.writeFile(resolvedPath, content, 'utf-8');
|
|
35
|
-
} else {
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function updateHermesConfig(): Promise<void> {
|
|
42
|
-
const configPath = resolvePath('~/.hermes/config.yaml');
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
let content = await fs.readFile(configPath, 'utf-8');
|
|
46
|
-
|
|
47
|
-
if (!content.includes('skills:')) {
|
|
48
|
-
const prefix = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
|
|
49
|
-
content += prefix + 'skills:\n external_dirs:\n - "./.hermes/skills"\n';
|
|
50
|
-
} else if (!content.includes('external_dirs:')) {
|
|
51
|
-
content = content.replace(/(skills:\s*\n)/, '$1 external_dirs:\n - "./.hermes/skills"\n');
|
|
52
|
-
} else if (!content.includes('./.hermes/skills')) {
|
|
53
|
-
content = content.replace(/(external_dirs:\s*\n)/, '$1 - "./.hermes/skills"\n');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
await fs.writeFile(configPath, content, 'utf-8');
|
|
57
|
-
} catch (error: any) {
|
|
58
|
-
if (error.code === 'ENOENT') {
|
|
59
|
-
const initialContent = `skills:\n external_dirs:\n - "./.hermes/skills"\n`;
|
|
60
|
-
await safeWriteFile('~/.hermes/config.yaml', initialContent);
|
|
61
|
-
} else {
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import * as fs from 'node:fs/promises';
|
|
5
|
-
import * as fsSync from 'node:fs';
|
|
6
|
-
import * as path from 'node:path';
|
|
7
|
-
import { Skill } from './transformers';
|
|
8
|
-
import { safeWriteFile } from './fs-adapters';
|
|
9
|
-
import chalk from 'chalk';
|
|
10
|
-
import ora from 'ora';
|
|
11
|
-
import Table from 'cli-table3';
|
|
12
|
-
|
|
13
|
-
const program = new Command();
|
|
14
|
-
|
|
15
|
-
const pkg = JSON.parse(fsSync.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
|
|
16
|
-
|
|
17
|
-
program
|
|
18
|
-
.name('@opendirectory.dev/skills')
|
|
19
|
-
.description(chalk.blue.bold('CLI to install OpenDirectory skills'))
|
|
20
|
-
.version(pkg.version);
|
|
21
|
-
|
|
22
|
-
const getProjectRoot = () => {
|
|
23
|
-
return path.resolve(__dirname, '..');
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
program
|
|
27
|
-
.command('list')
|
|
28
|
-
.description('List available skills in the Open Directory registry')
|
|
29
|
-
.action(async () => {
|
|
30
|
-
const spinner = ora('Fetching available skills...').start();
|
|
31
|
-
try {
|
|
32
|
-
const root = getProjectRoot();
|
|
33
|
-
const registryPath = path.join(root, 'registry.json');
|
|
34
|
-
|
|
35
|
-
let skills: any[] = [];
|
|
36
|
-
try {
|
|
37
|
-
const registryContent = await fs.readFile(registryPath, 'utf-8');
|
|
38
|
-
skills = JSON.parse(registryContent);
|
|
39
|
-
} catch (e) {
|
|
40
|
-
const skillsDir = path.join(root, 'skills');
|
|
41
|
-
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
42
|
-
skills = entries
|
|
43
|
-
.filter(entry => entry.isDirectory())
|
|
44
|
-
.map(entry => ({ name: entry.name, description: `Skill: ${entry.name}` }));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
spinner.stop();
|
|
48
|
-
console.log(chalk.green('Successfully loaded Open Directory registry!\n'));
|
|
49
|
-
|
|
50
|
-
const table = new Table({
|
|
51
|
-
head: [chalk.cyan.bold('Skill Name'), chalk.cyan.bold('Description')],
|
|
52
|
-
colWidths: [35, 75],
|
|
53
|
-
wordWrap: true
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
for (const skill of skills) {
|
|
57
|
-
let desc = skill.description || '';
|
|
58
|
-
desc = desc.replace(/<img[^>]*>/g, '').trim();
|
|
59
|
-
if (desc.length > 100) desc = desc.substring(0, 97) + '...';
|
|
60
|
-
|
|
61
|
-
table.push([chalk.yellow(skill.name), desc]);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
console.log(table.toString());
|
|
65
|
-
console.log(chalk.gray(`\nRun \`${chalk.white('npx "@opendirectory.dev/skills" install <skill-name> --target <agent>')}\` to install a skill.`));
|
|
66
|
-
|
|
67
|
-
} catch (error) {
|
|
68
|
-
spinner.stop();
|
|
69
|
-
console.error(chalk.red('Failed to list skills.'));
|
|
70
|
-
console.error(error);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
program
|
|
75
|
-
.command('install <skill>')
|
|
76
|
-
.description('Install a skill for your AI agent')
|
|
77
|
-
.requiredOption('-t, --target <tool>', 'Target agent (opencode, claude, codex, gemini, anti-gravity, openclaw, hermes)')
|
|
78
|
-
.action(async (skillName, options) => {
|
|
79
|
-
const spinner = ora(`Installing ${chalk.yellow(skillName)}...`).start();
|
|
80
|
-
try {
|
|
81
|
-
const root = getProjectRoot();
|
|
82
|
-
const repoDir = path.join(root, 'skills', skillName);
|
|
83
|
-
|
|
84
|
-
let skillDir = repoDir;
|
|
85
|
-
let skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
await fs.access(skillMdPath);
|
|
89
|
-
} catch (e) {
|
|
90
|
-
try {
|
|
91
|
-
const entries = await fs.readdir(repoDir, { withFileTypes: true });
|
|
92
|
-
for (const entry of entries) {
|
|
93
|
-
if (entry.isDirectory()) {
|
|
94
|
-
const possiblePath = path.join(repoDir, entry.name, 'SKILL.md');
|
|
95
|
-
try {
|
|
96
|
-
await fs.access(possiblePath);
|
|
97
|
-
skillDir = path.join(repoDir, entry.name);
|
|
98
|
-
skillMdPath = possiblePath;
|
|
99
|
-
break;
|
|
100
|
-
} catch (err) {}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (skillDir === repoDir) {
|
|
104
|
-
for (const entry of entries) {
|
|
105
|
-
if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
106
|
-
const subDir = path.join(repoDir, entry.name);
|
|
107
|
-
const subEntries = await fs.readdir(subDir, { withFileTypes: true });
|
|
108
|
-
for (const subEntry of subEntries) {
|
|
109
|
-
if (subEntry.isDirectory()) {
|
|
110
|
-
const possiblePath = path.join(subDir, subEntry.name, 'SKILL.md');
|
|
111
|
-
try {
|
|
112
|
-
await fs.access(possiblePath);
|
|
113
|
-
skillDir = path.join(subDir, subEntry.name);
|
|
114
|
-
skillMdPath = possiblePath;
|
|
115
|
-
break;
|
|
116
|
-
} catch (err) {}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
} catch (dirErr) {
|
|
123
|
-
spinner.stop();
|
|
124
|
-
console.error(chalk.red(`Error: Repository '${skillName}' not found.`));
|
|
125
|
-
console.log(chalk.gray(`Try running \`${chalk.white('npx "@opendirectory.dev/skills" list')}\` to see available skills.`));
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
await fs.access(skillMdPath);
|
|
132
|
-
} catch (e) {
|
|
133
|
-
spinner.stop();
|
|
134
|
-
console.error(chalk.red(`Error: Skill '${skillName}' missing SKILL.md in registry.`));
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const actualSkillFolderName = path.basename(skillDir);
|
|
139
|
-
const finalSkillName = actualSkillFolderName === skillName ? skillName : actualSkillFolderName;
|
|
140
|
-
|
|
141
|
-
const target = options.target.toLowerCase();
|
|
142
|
-
|
|
143
|
-
const validTargets = ['opencode', 'claude', 'codex', 'gemini', 'anti-gravity', 'openclaw', 'hermes'];
|
|
144
|
-
|
|
145
|
-
if (validTargets.includes(target)) {
|
|
146
|
-
let targetFolder = '';
|
|
147
|
-
if (target === 'opencode') targetFolder = `~/.config/opencode/skills/${finalSkillName}`;
|
|
148
|
-
if (target === 'claude') targetFolder = `~/.claude/skills/${finalSkillName}`;
|
|
149
|
-
if (target === 'codex') targetFolder = `~/.codex/skills/${finalSkillName}`;
|
|
150
|
-
if (target === 'gemini') targetFolder = `~/.gemini/skills/${finalSkillName}`;
|
|
151
|
-
if (target === 'anti-gravity') targetFolder = `~/.gemini/antigravity/skills/${finalSkillName}`;
|
|
152
|
-
if (target === 'openclaw') targetFolder = `~/.openclaw/skills/${finalSkillName}`;
|
|
153
|
-
if (target === 'hermes') targetFolder = `~/.hermes/skills/${finalSkillName}`;
|
|
154
|
-
|
|
155
|
-
const { resolvePath } = require('./fs-adapters');
|
|
156
|
-
const resolvedDest = resolvePath(targetFolder);
|
|
157
|
-
await fs.mkdir(resolvedDest, { recursive: true });
|
|
158
|
-
await fs.cp(skillDir, resolvedDest, { recursive: true });
|
|
159
|
-
|
|
160
|
-
spinner.stop();
|
|
161
|
-
console.log(chalk.green(`Successfully installed ${chalk.bold(finalSkillName)}!`));
|
|
162
|
-
console.log(`\n ${chalk.cyan('Agent:')} ${target}`);
|
|
163
|
-
console.log(` ${chalk.cyan('Scope:')} Global`);
|
|
164
|
-
console.log(` ${chalk.cyan('Path:')} ${targetFolder}\n`);
|
|
165
|
-
} else {
|
|
166
|
-
spinner.stop();
|
|
167
|
-
console.error(chalk.red(`Error: Unsupported target '${target}'.`));
|
|
168
|
-
console.log(chalk.gray(`Supported targets: ${validTargets.join(', ')}`));
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
} catch (error) {
|
|
172
|
-
spinner.stop();
|
|
173
|
-
console.error(chalk.red('Failed to install skill.'));
|
|
174
|
-
console.error(error);
|
|
175
|
-
process.exit(1);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
program.parse();
|
package/src/transformers.ts
DELETED