@chakresh/kresh 0.1.14 → 0.1.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chakresh/kresh",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "bin": {
5
5
  "kresh": "./src/index.js"
6
6
  },
@@ -60,8 +60,23 @@ export async function installSkill(skillSlug, isRetry = false) {
60
60
  }
61
61
  }
62
62
 
63
+ const { agentType } = await inquirer.prompt([
64
+ {
65
+ type: 'list',
66
+ name: 'agentType',
67
+ message: 'Which AI Agent are you installing this skill for?',
68
+ choices: [
69
+ { name: 'Antigravity (.agents/skills)', value: '.agents/skills' },
70
+ { name: 'Claude Code (.claude/skills)', value: '.claude/skills' },
71
+ { name: 'Codex (.codex/skills)', value: '.codex/skills' },
72
+ { name: 'Cursor (.cursor/skills)', value: '.cursor/skills' },
73
+ { name: 'Standard / Other (skills)', value: 'skills' }
74
+ ]
75
+ }
76
+ ]);
77
+
63
78
  spinner.start('Writing skill files locally...');
64
- const savedDir = await writeLocalSkill(skillSlug, skillContent, metadata);
79
+ const savedDir = await writeLocalSkill(skillSlug, skillContent, metadata, agentType);
65
80
 
66
81
  spinner.succeed(`Successfully installed ${logger.bold(metadata.name)} (v${metadata.currentVersion}) by @${metadata.ownerUsername}`);
67
82
  logger.info(`Saved to: ${logger.bold(savedDir)}`);
@@ -1,7 +1,7 @@
1
1
  import axios from 'axios';
2
2
  import { getToken } from './auth.js';
3
3
 
4
- const baseURL = process.env.KRESH_API_URL || 'http://localhost:3000'; // Assume localhost for local testing
4
+ const baseURL = process.env.KRESH_API_URL || 'https://kresh.vercel.app';
5
5
 
6
6
  export const api = axios.create({
7
7
  baseURL,
@@ -1,6 +1,8 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
 
4
+ const BASE_DIRS = ['skills', '.agents/skills', '.claude/skills', '.codex/skills', '.cursor/skills'];
5
+
4
6
  /**
5
7
  * Helper to find the workspace or project root directory by scanning up.
6
8
  */
@@ -49,140 +51,152 @@ export async function getWorkspaceRoot(startDir = process.cwd()) {
49
51
  /**
50
52
  * Writes the SKILL.md and metadata.json files directly in a folder named after the skill's slug (excluding @owner scope folder) inside the skills folder.
51
53
  */
52
- export async function writeLocalSkill(slug, skillContent, metadata) {
54
+ export async function writeLocalSkill(slug, skillContent, metadata, baseDir = 'skills') {
53
55
  try {
54
56
  const rootDir = await getWorkspaceRoot();
55
57
  const folderName = (slug || metadata.slug).split('/').pop();
56
- const targetDir = path.join(rootDir, 'skills', folderName);
58
+ const targetDir = path.join(rootDir, baseDir, folderName);
57
59
 
58
60
  await fs.mkdir(targetDir, { recursive: true });
59
61
  await fs.writeFile(path.join(targetDir, 'SKILL.md'), skillContent, 'utf8');
60
62
  await fs.writeFile(path.join(targetDir, 'metadata.json'), JSON.stringify(metadata, null, 2), 'utf8');
61
63
  return targetDir;
62
64
  } catch (error) {
63
- console.error('Failed to write skill files in the skills directory:', error);
65
+ console.error(`Failed to write skill files in the ${baseDir} directory:`, error);
64
66
  throw new Error(`Local file system write failed: ${error.message}`);
65
67
  }
66
68
  }
67
69
 
68
- /**
69
- * Reads the local metadata.json of a specific skill if it exists.
70
- */
71
70
  export async function readLocalSkillMetadata(slug) {
72
- try {
73
- const rootDir = await getWorkspaceRoot();
74
- const folderName = slug.split('/').pop();
75
- const metadataPath = path.join(rootDir, 'skills', folderName, 'metadata.json');
76
- const data = await fs.readFile(metadataPath, 'utf8');
77
- return JSON.parse(data);
78
- } catch (error) {
79
- // Also try legacy path for backwards compatibility
71
+ const rootDir = await getWorkspaceRoot();
72
+ const folderName = slug.split('/').pop();
73
+
74
+ for (const baseDir of BASE_DIRS) {
80
75
  try {
81
- const rootDir = await getWorkspaceRoot();
82
- const legacyPath = path.join(rootDir, 'skills', slug, 'metadata.json');
83
- const data = await fs.readFile(legacyPath, 'utf8');
76
+ const metadataPath = path.join(rootDir, baseDir, folderName, 'metadata.json');
77
+ const data = await fs.readFile(metadataPath, 'utf8');
84
78
  return JSON.parse(data);
85
- } catch (e) {
86
- return null;
79
+ } catch (error) {
80
+ // Also try legacy path for backwards compatibility
81
+ try {
82
+ const legacyPath = path.join(rootDir, baseDir, slug, 'metadata.json');
83
+ const data = await fs.readFile(legacyPath, 'utf8');
84
+ return JSON.parse(data);
85
+ } catch (e) {
86
+ // Continue to the next baseDir
87
+ }
87
88
  }
88
89
  }
90
+ return null;
89
91
  }
90
92
 
91
- /**
92
- * Removes the skill directory.
93
- */
94
93
  export async function removeLocalSkill(slug) {
95
94
  try {
96
95
  const rootDir = await getWorkspaceRoot();
97
96
  const folderName = slug.split('/').pop();
98
- const targetDir = path.join(rootDir, 'skills', folderName);
99
- await fs.rm(targetDir, { recursive: true, force: true });
100
-
101
- // Also clean up legacy directory if it exists
102
- const legacyDir = path.join(rootDir, 'skills', slug);
103
- await fs.rm(legacyDir, { recursive: true, force: true });
104
97
 
105
- // Clean up empty parent directory (e.g. @username) if it becomes empty
106
- if (slug.includes('/')) {
107
- const parts = slug.split('/');
108
- const parentDir = path.join(rootDir, 'skills', parts[0]);
109
- try {
110
- const files = await fs.readdir(parentDir);
111
- if (files.length === 0) {
112
- await fs.rmdir(parentDir);
98
+ for (const baseDir of BASE_DIRS) {
99
+ const targetDir = path.join(rootDir, baseDir, folderName);
100
+ await fs.rm(targetDir, { recursive: true, force: true });
101
+
102
+ // Also clean up legacy directory if it exists
103
+ const legacyDir = path.join(rootDir, baseDir, slug);
104
+ await fs.rm(legacyDir, { recursive: true, force: true });
105
+
106
+ // Clean up empty parent directory (e.g. @username) if it becomes empty
107
+ if (slug.includes('/')) {
108
+ const parts = slug.split('/');
109
+ const parentDir = path.join(rootDir, baseDir, parts[0]);
110
+ try {
111
+ const files = await fs.readdir(parentDir);
112
+ if (files.length === 0) {
113
+ await fs.rmdir(parentDir);
114
+ }
115
+ } catch (e) {
116
+ // Ignore
113
117
  }
114
- } catch (e) {
115
- // Ignore
116
118
  }
117
119
  }
118
120
  return true;
119
121
  } catch (error) {
120
- console.error('Failed to remove skill files from the skills directory:', error);
122
+ console.error('Failed to remove skill files from the skills directories:', error);
121
123
  throw new Error(`Local file system removal failed: ${error.message}`);
122
124
  }
123
125
  }
124
126
 
125
- /**
126
- * Lists all installed skills by inspecting the skills directory.
127
- */
128
127
  export async function listLocalSkills() {
129
128
  try {
130
129
  const rootDir = await getWorkspaceRoot();
131
- const skillsDir = path.join(rootDir, 'skills');
132
- let entries = [];
133
- try {
134
- entries = await fs.readdir(skillsDir, { withFileTypes: true });
135
- } catch (e) {
136
- if (e.code === 'ENOENT') return [];
137
- throw e;
138
- }
139
-
140
130
  const skills = [];
141
- for (const entry of entries) {
142
- if (entry.isDirectory()) {
143
- if (entry.name.startsWith('@')) {
144
- // Legacy support: It's a user scope directory, scan subdirectories inside it
145
- const scopeDir = path.join(skillsDir, entry.name);
146
- let subEntries = [];
147
- try {
148
- subEntries = await fs.readdir(scopeDir, { withFileTypes: true });
149
- } catch (e) {
150
- continue;
151
- }
152
-
153
- for (const subEntry of subEntries) {
154
- if (subEntry.isDirectory()) {
155
- const scopedSlug = `${entry.name}/${subEntry.name}`;
156
- const metadata = await readLocalSkillMetadata(scopedSlug);
157
- if (metadata) {
131
+ const seenSlugs = new Set();
132
+
133
+ for (const baseDir of BASE_DIRS) {
134
+ const skillsDir = path.join(rootDir, baseDir);
135
+ let entries = [];
136
+ try {
137
+ entries = await fs.readdir(skillsDir, { withFileTypes: true });
138
+ } catch (e) {
139
+ continue;
140
+ }
141
+
142
+ for (const entry of entries) {
143
+ if (entry.isDirectory()) {
144
+ if (entry.name.startsWith('@')) {
145
+ // Legacy support: It's a user scope directory, scan subdirectories inside it
146
+ const scopeDir = path.join(skillsDir, entry.name);
147
+ let subEntries = [];
148
+ try {
149
+ subEntries = await fs.readdir(scopeDir, { withFileTypes: true });
150
+ } catch (e) {
151
+ continue;
152
+ }
153
+
154
+ for (const subEntry of subEntries) {
155
+ if (subEntry.isDirectory()) {
156
+ const scopedSlug = `${entry.name}/${subEntry.name}`;
157
+ if (seenSlugs.has(scopedSlug)) continue;
158
+
159
+ try {
160
+ const metadataPath = path.join(skillsDir, entry.name, subEntry.name, 'metadata.json');
161
+ const data = await fs.readFile(metadataPath, 'utf8');
162
+ const metadata = JSON.parse(data);
163
+ if (metadata) {
164
+ skills.push({
165
+ slug: metadata.slug || scopedSlug,
166
+ installed: true,
167
+ version: metadata.version || metadata.currentVersion || 'unknown',
168
+ name: metadata.name || 'unknown',
169
+ description: metadata.description || ''
170
+ });
171
+ seenSlugs.add(scopedSlug);
172
+ }
173
+ } catch (e) {
174
+ // Ignore
175
+ }
176
+ }
177
+ }
178
+ } else {
179
+ // New format: Directly under skills/
180
+ try {
181
+ const metadataPath = path.join(skillsDir, entry.name, 'metadata.json');
182
+ const data = await fs.readFile(metadataPath, 'utf8');
183
+ const metadata = JSON.parse(data);
184
+ const slug = metadata.slug || entry.name;
185
+
186
+ if (metadata && !seenSlugs.has(slug)) {
158
187
  skills.push({
159
- slug: metadata.slug || scopedSlug,
188
+ slug: slug,
160
189
  installed: true,
161
190
  version: metadata.version || metadata.currentVersion || 'unknown',
162
191
  name: metadata.name || 'unknown',
163
192
  description: metadata.description || ''
164
193
  });
194
+ seenSlugs.add(slug);
165
195
  }
196
+ } catch (e) {
197
+ // Ignore if metadata is invalid/missing
166
198
  }
167
199
  }
168
- } else {
169
- // New format: Directly under skills/
170
- try {
171
- const metadataPath = path.join(skillsDir, entry.name, 'metadata.json');
172
- const data = await fs.readFile(metadataPath, 'utf8');
173
- const metadata = JSON.parse(data);
174
- if (metadata) {
175
- skills.push({
176
- slug: metadata.slug || entry.name,
177
- installed: true,
178
- version: metadata.version || metadata.currentVersion || 'unknown',
179
- name: metadata.name || 'unknown',
180
- description: metadata.description || ''
181
- });
182
- }
183
- } catch (e) {
184
- // Ignore if metadata is invalid/missing
185
- }
186
200
  }
187
201
  }
188
202
  }