@chakresh/kresh 0.1.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/package.json +15 -0
- package/src/commands/install.js +34 -0
- package/src/commands/ls.js +23 -0
- package/src/commands/publish.js +13 -0
- package/src/commands/remove.js +20 -0
- package/src/commands/search.js +37 -0
- package/src/index.js +56 -0
- package/src/services/api.js +12 -0
- package/src/services/filesystem.js +83 -0
- package/src/utils/logger.js +10 -0
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chakresh/kresh",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"bin": {
|
|
5
|
+
"kresh": "./src/index.js"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"commander": "^11.1.0",
|
|
10
|
+
"axios": "^1.6.8",
|
|
11
|
+
"chalk": "^5.3.0",
|
|
12
|
+
"ora": "^8.0.1",
|
|
13
|
+
"inquirer": "^9.2.16"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { api } from '../services/api.js';
|
|
5
|
+
import { writeLocalSkill } from '../services/filesystem.js';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Installs a skill from the registry locally.
|
|
10
|
+
*/
|
|
11
|
+
export async function installSkill(skillSlug) {
|
|
12
|
+
const spinner = ora(`Fetching skill "${skillSlug}"...`).start();
|
|
13
|
+
try {
|
|
14
|
+
const response = await api.get(`/api/skills/${skillSlug}`);
|
|
15
|
+
const { skillContent, ...metadata } = response.data;
|
|
16
|
+
|
|
17
|
+
spinner.text = 'Writing skill files locally...';
|
|
18
|
+
const savedDir = await writeLocalSkill(skillSlug, skillContent, metadata);
|
|
19
|
+
|
|
20
|
+
spinner.succeed(`Successfully installed ${logger.bold(metadata.name)} (v${metadata.currentVersion}) by @${metadata.ownerUsername}`);
|
|
21
|
+
logger.info(`Saved to: ${logger.bold(savedDir)}`);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
spinner.fail(`Installation failed for "${skillSlug}"`);
|
|
24
|
+
if (error.response) {
|
|
25
|
+
if (error.response.status === 404) {
|
|
26
|
+
logger.error(`Skill "${skillSlug}" was not found in the registry.`);
|
|
27
|
+
} else {
|
|
28
|
+
logger.error(`Registry error: ${error.response.data?.error || error.response.statusText}`);
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
logger.error(`Connection error: ${error.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { listLocalSkills } from '../services/filesystem.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Lists all installed skills locally.
|
|
6
|
+
*/
|
|
7
|
+
export async function listInstalledSkills() {
|
|
8
|
+
const skills = await listLocalSkills();
|
|
9
|
+
|
|
10
|
+
if (skills.length === 0) {
|
|
11
|
+
logger.info('No skills installed locally. Run `kresh install <skill>` to install one.');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
logger.success(`Installed skills (${skills.length}):\n`);
|
|
16
|
+
skills.forEach((skill) => {
|
|
17
|
+
console.log(` • ${logger.bold(skill.name)} (${logger.dim(skill.slug)}) [v${skill.version}]`);
|
|
18
|
+
if (skill.description) {
|
|
19
|
+
console.log(` ${logger.dim(skill.description)}`);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
console.log();
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { logger } from '../utils/logger.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Explains how users can publish a skill to the registry.
|
|
5
|
+
*/
|
|
6
|
+
export async function publishSkill() {
|
|
7
|
+
logger.info("To publish an intelligence skill, please follow these steps:");
|
|
8
|
+
console.log(" 1. Create a markdown file named SKILL.md specifying agent instructions.");
|
|
9
|
+
console.log(" 2. Open the publisher page: http://localhost:3000/dashboard/publish");
|
|
10
|
+
console.log(" 3. Enter the name, category, version, and upload or paste your SKILL.md content.");
|
|
11
|
+
console.log();
|
|
12
|
+
logger.success("Once published, anyone can install it with `kresh install <slug>`.");
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import { removeLocalSkill, readLocalSkillMetadata } from '../services/filesystem.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Removes/uninstalls a skill locally.
|
|
7
|
+
*/
|
|
8
|
+
export async function removeSkill(skillSlug) {
|
|
9
|
+
const metadata = await readLocalSkillMetadata(skillSlug);
|
|
10
|
+
const displayName = metadata ? metadata.name : skillSlug;
|
|
11
|
+
const spinner = ora(`Uninstalling local skill "${displayName}"...`).start();
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
await removeLocalSkill(skillSlug);
|
|
15
|
+
spinner.succeed(`Successfully uninstalled "${logger.bold(displayName)}"`);
|
|
16
|
+
} catch (error) {
|
|
17
|
+
spinner.fail(`Failed to uninstall "${skillSlug}"`);
|
|
18
|
+
logger.error(error.message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import { api } from '../services/api.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Searches the registry for skills matching the query.
|
|
7
|
+
*/
|
|
8
|
+
export async function searchSkills(query) {
|
|
9
|
+
const spinner = ora(`Searching registry for "${query}"...`).start();
|
|
10
|
+
try {
|
|
11
|
+
const response = await api.get(`/api/skills`, { params: { q: query } });
|
|
12
|
+
const skills = response.data;
|
|
13
|
+
|
|
14
|
+
if (skills.length === 0) {
|
|
15
|
+
spinner.info(`No skills found matching "${query}"`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
spinner.succeed(`Found ${skills.length} matching skill(s):\n`);
|
|
20
|
+
|
|
21
|
+
skills.forEach((skill) => {
|
|
22
|
+
console.log(` ${logger.bold(skill.name)} (${logger.dim(skill.slug)})`);
|
|
23
|
+
console.log(` ${logger.dim('Version:')} v${skill.currentVersion || '1.0.0'} | ${logger.dim('Publisher:')} @${skill.ownerUsername || 'unknown'}`);
|
|
24
|
+
if (skill.description) {
|
|
25
|
+
console.log(` ${skill.description}`);
|
|
26
|
+
}
|
|
27
|
+
console.log();
|
|
28
|
+
});
|
|
29
|
+
} catch (error) {
|
|
30
|
+
spinner.fail(`Search query failed for "${query}"`);
|
|
31
|
+
if (error.response) {
|
|
32
|
+
logger.error(`Registry error: ${error.response.data?.error || error.response.statusText}`);
|
|
33
|
+
} else {
|
|
34
|
+
logger.error(`Connection error: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { installSkill } from './commands/install.js';
|
|
5
|
+
import { searchSkills } from './commands/search.js';
|
|
6
|
+
import { listInstalledSkills } from './commands/ls.js';
|
|
7
|
+
import { removeSkill } from './commands/remove.js';
|
|
8
|
+
import { publishSkill } from './commands/publish.js';
|
|
9
|
+
|
|
10
|
+
const program = new Command();
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('kresh')
|
|
14
|
+
.description('Install and manage intelligence skills')
|
|
15
|
+
.version('0.1.0');
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.command('install <skill>')
|
|
19
|
+
.alias('i')
|
|
20
|
+
.description('Install a skill locally')
|
|
21
|
+
.action(async (skill) => {
|
|
22
|
+
await installSkill(skill);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
program
|
|
26
|
+
.command('search <query>')
|
|
27
|
+
.alias('s')
|
|
28
|
+
.description('Search skills in the registry')
|
|
29
|
+
.action(async (query) => {
|
|
30
|
+
await searchSkills(query);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command('ls')
|
|
35
|
+
.alias('list')
|
|
36
|
+
.description('List installed skills')
|
|
37
|
+
.action(async () => {
|
|
38
|
+
await listInstalledSkills();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
program
|
|
42
|
+
.command('remove <skill>')
|
|
43
|
+
.alias('rm')
|
|
44
|
+
.description('Remove an installed skill')
|
|
45
|
+
.action(async (skill) => {
|
|
46
|
+
await removeSkill(skill);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
program
|
|
50
|
+
.command('publish')
|
|
51
|
+
.description('Publish a skill')
|
|
52
|
+
.action(async () => {
|
|
53
|
+
await publishSkill();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
program.parse();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
const baseURL = process.env.KRESH_API_URL || 'http://localhost:3000';
|
|
4
|
+
|
|
5
|
+
export const api = axios.create({
|
|
6
|
+
baseURL,
|
|
7
|
+
timeout: 10000,
|
|
8
|
+
headers: {
|
|
9
|
+
'Accept': 'application/json',
|
|
10
|
+
'Content-Type': 'application/json'
|
|
11
|
+
}
|
|
12
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Writes the SKILL.md and metadata.json files directly in a folder named after the skill's slug inside the skills folder.
|
|
6
|
+
*/
|
|
7
|
+
export async function writeLocalSkill(slug, skillContent, metadata) {
|
|
8
|
+
try {
|
|
9
|
+
// Sanitize folder name, use slug
|
|
10
|
+
const folderName = slug || metadata.slug;
|
|
11
|
+
const targetDir = path.join(process.cwd(), 'skills', folderName);
|
|
12
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
13
|
+
await fs.writeFile(path.join(targetDir, 'SKILL.md'), skillContent, 'utf8');
|
|
14
|
+
await fs.writeFile(path.join(targetDir, 'metadata.json'), JSON.stringify(metadata, null, 2), 'utf8');
|
|
15
|
+
return targetDir;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error('Failed to write skill files in the skills directory:', error);
|
|
18
|
+
throw new Error(`Local file system write failed: ${error.message}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Reads the local metadata.json of a specific skill if it exists.
|
|
24
|
+
*/
|
|
25
|
+
export async function readLocalSkillMetadata(slug) {
|
|
26
|
+
try {
|
|
27
|
+
const metadataPath = path.join(process.cwd(), 'skills', slug, 'metadata.json');
|
|
28
|
+
const data = await fs.readFile(metadataPath, 'utf8');
|
|
29
|
+
return JSON.parse(data);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Removes the skill directory.
|
|
37
|
+
*/
|
|
38
|
+
export async function removeLocalSkill(slug) {
|
|
39
|
+
try {
|
|
40
|
+
const targetDir = path.join(process.cwd(), 'skills', slug);
|
|
41
|
+
await fs.rm(targetDir, { recursive: true, force: true });
|
|
42
|
+
return true;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Failed to remove skill files from the skills directory:', error);
|
|
45
|
+
throw new Error(`Local file system removal failed: ${error.message}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Lists all installed skills by inspecting the skills directory.
|
|
51
|
+
*/
|
|
52
|
+
export async function listLocalSkills() {
|
|
53
|
+
try {
|
|
54
|
+
const skillsDir = path.join(process.cwd(), 'skills');
|
|
55
|
+
let entries = [];
|
|
56
|
+
try {
|
|
57
|
+
entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
58
|
+
} catch (e) {
|
|
59
|
+
if (e.code === 'ENOENT') return [];
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const skills = [];
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
if (entry.isDirectory()) {
|
|
66
|
+
const metadata = await readLocalSkillMetadata(entry.name);
|
|
67
|
+
if (metadata) {
|
|
68
|
+
skills.push({
|
|
69
|
+
slug: metadata.slug || entry.name,
|
|
70
|
+
installed: true,
|
|
71
|
+
version: metadata.version || metadata.currentVersion || 'unknown',
|
|
72
|
+
name: metadata.name || 'unknown',
|
|
73
|
+
description: metadata.description || ''
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return skills;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('Failed to list local skills:', error);
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export const logger = {
|
|
4
|
+
info: (msg) => console.log(chalk.blue('ℹ'), msg),
|
|
5
|
+
success: (msg) => console.log(chalk.green('✔'), msg),
|
|
6
|
+
warning: (msg) => console.log(chalk.yellow('⚠'), msg),
|
|
7
|
+
error: (msg) => console.log(chalk.red('✖'), msg),
|
|
8
|
+
bold: (msg) => chalk.bold(msg),
|
|
9
|
+
dim: (msg) => chalk.dim(msg)
|
|
10
|
+
};
|