ikie-cli 0.1.33 → 0.1.35
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 +26 -9
- package/dist/agent.d.ts +44 -0
- package/dist/agent.js +372 -120
- package/dist/config.d.ts +8 -0
- package/dist/config.js +4 -0
- package/dist/index.js +37 -1
- package/dist/mcp-manager.d.ts +75 -89
- package/dist/mcp-manager.js +710 -304
- package/dist/repl.js +297 -71
- package/dist/skills.d.ts +16 -0
- package/dist/skills.js +83 -6
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +21 -4
- package/dist/tools.d.ts +1 -0
- package/dist/tools.js +115 -166
- package/dist/tree.d.ts +19 -0
- package/dist/tree.js +266 -0
- package/package.json +2 -1
package/dist/tree.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { readdirSync, statSync, existsSync } from 'fs';
|
|
2
|
+
import { join, extname } from 'path';
|
|
3
|
+
import { c } from './theme.js';
|
|
4
|
+
const DEFAULT_EXCLUDE = [
|
|
5
|
+
'node_modules',
|
|
6
|
+
'.git',
|
|
7
|
+
'dist',
|
|
8
|
+
'build',
|
|
9
|
+
'.next',
|
|
10
|
+
'.nuxt',
|
|
11
|
+
'coverage',
|
|
12
|
+
'.cache',
|
|
13
|
+
'tmp',
|
|
14
|
+
'temp',
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Get icon for file based on extension
|
|
18
|
+
*/
|
|
19
|
+
function getFileIcon(filename, isDirectory) {
|
|
20
|
+
if (isDirectory)
|
|
21
|
+
return '📁';
|
|
22
|
+
const ext = extname(filename).toLowerCase();
|
|
23
|
+
const name = filename.toLowerCase();
|
|
24
|
+
// Special files
|
|
25
|
+
if (name === 'package.json')
|
|
26
|
+
return '📦';
|
|
27
|
+
if (name === 'package-lock.json')
|
|
28
|
+
return '🔒';
|
|
29
|
+
if (name === 'yarn.lock')
|
|
30
|
+
return '🔒';
|
|
31
|
+
if (name === 'tsconfig.json')
|
|
32
|
+
return '⚙️';
|
|
33
|
+
if (name === '.gitignore')
|
|
34
|
+
return '🚫';
|
|
35
|
+
if (name === 'readme.md' || name === 'readme')
|
|
36
|
+
return '📖';
|
|
37
|
+
if (name === 'license' || name === 'license.md')
|
|
38
|
+
return '📜';
|
|
39
|
+
if (name === '.env' || name.startsWith('.env.'))
|
|
40
|
+
return '🔑';
|
|
41
|
+
if (name === 'dockerfile')
|
|
42
|
+
return '🐳';
|
|
43
|
+
// By extension
|
|
44
|
+
switch (ext) {
|
|
45
|
+
case '.ts':
|
|
46
|
+
case '.tsx': return '🔷';
|
|
47
|
+
case '.js':
|
|
48
|
+
case '.jsx': return '🟨';
|
|
49
|
+
case '.json': return '📋';
|
|
50
|
+
case '.md': return '📝';
|
|
51
|
+
case '.css':
|
|
52
|
+
case '.scss':
|
|
53
|
+
case '.sass':
|
|
54
|
+
case '.less': return '🎨';
|
|
55
|
+
case '.html': return '🌐';
|
|
56
|
+
case '.py': return '🐍';
|
|
57
|
+
case '.rs': return '🦀';
|
|
58
|
+
case '.go': return '🐹';
|
|
59
|
+
case '.java': return '☕';
|
|
60
|
+
case '.cpp':
|
|
61
|
+
case '.c':
|
|
62
|
+
case '.h': return '⚡';
|
|
63
|
+
case '.sh':
|
|
64
|
+
case '.bash':
|
|
65
|
+
case '.zsh': return '🔧';
|
|
66
|
+
case '.yml':
|
|
67
|
+
case '.yaml': return '⚙️';
|
|
68
|
+
case '.xml': return '📰';
|
|
69
|
+
case '.sql': return '🗄️';
|
|
70
|
+
case '.png':
|
|
71
|
+
case '.jpg':
|
|
72
|
+
case '.jpeg':
|
|
73
|
+
case '.gif':
|
|
74
|
+
case '.svg':
|
|
75
|
+
case '.webp': return '🖼️';
|
|
76
|
+
case '.mp4':
|
|
77
|
+
case '.mov':
|
|
78
|
+
case '.avi': return '🎬';
|
|
79
|
+
case '.mp3':
|
|
80
|
+
case '.wav':
|
|
81
|
+
case '.ogg': return '🎵';
|
|
82
|
+
case '.zip':
|
|
83
|
+
case '.tar':
|
|
84
|
+
case '.gz':
|
|
85
|
+
case '.rar': return '📦';
|
|
86
|
+
case '.pdf': return '📕';
|
|
87
|
+
case '.txt': return '📄';
|
|
88
|
+
default: return '📄';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format file size in human-readable format
|
|
93
|
+
*/
|
|
94
|
+
function formatSize(bytes) {
|
|
95
|
+
if (bytes < 1024)
|
|
96
|
+
return `${bytes}B`;
|
|
97
|
+
if (bytes < 1024 * 1024)
|
|
98
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
99
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
100
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
101
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get color for file based on type
|
|
105
|
+
*/
|
|
106
|
+
function getFileColor(filename, isDirectory) {
|
|
107
|
+
if (isDirectory)
|
|
108
|
+
return c.primary.bold;
|
|
109
|
+
const ext = extname(filename).toLowerCase();
|
|
110
|
+
const name = filename.toLowerCase();
|
|
111
|
+
// Hidden files
|
|
112
|
+
if (name.startsWith('.'))
|
|
113
|
+
return c.dim;
|
|
114
|
+
// Config files
|
|
115
|
+
if (name.includes('config') || ext === '.json' || ext === '.yml' || ext === '.yaml') {
|
|
116
|
+
return c.secondary;
|
|
117
|
+
}
|
|
118
|
+
// Source code
|
|
119
|
+
if (['.ts', '.tsx', '.js', '.jsx', '.py', '.rs', '.go', '.java'].includes(ext)) {
|
|
120
|
+
return c.white;
|
|
121
|
+
}
|
|
122
|
+
// Documentation
|
|
123
|
+
if (ext === '.md' || name === 'readme') {
|
|
124
|
+
return c.info;
|
|
125
|
+
}
|
|
126
|
+
// Executables and scripts
|
|
127
|
+
if (['.sh', '.bash', '.zsh'].includes(ext)) {
|
|
128
|
+
return c.success;
|
|
129
|
+
}
|
|
130
|
+
return c.muted;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Build tree structure recursively
|
|
134
|
+
*/
|
|
135
|
+
function buildTree(dirPath, prefix, options, results) {
|
|
136
|
+
const currentDepth = options.currentDepth || 0;
|
|
137
|
+
const maxDepth = options.maxDepth || 3;
|
|
138
|
+
const showHidden = options.showHidden || false;
|
|
139
|
+
const showSize = options.showSize || false;
|
|
140
|
+
const exclude = [...DEFAULT_EXCLUDE, ...(options.exclude || [])];
|
|
141
|
+
if (currentDepth >= maxDepth)
|
|
142
|
+
return;
|
|
143
|
+
let entries;
|
|
144
|
+
try {
|
|
145
|
+
entries = readdirSync(dirPath);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// Filter entries
|
|
151
|
+
entries = entries.filter(entry => {
|
|
152
|
+
// Exclude hidden files unless showHidden is true
|
|
153
|
+
if (!showHidden && entry.startsWith('.'))
|
|
154
|
+
return false;
|
|
155
|
+
// Exclude specified patterns
|
|
156
|
+
if (exclude.includes(entry))
|
|
157
|
+
return false;
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
// Sort: directories first, then files, alphabetically within each group
|
|
161
|
+
entries.sort((a, b) => {
|
|
162
|
+
const aPath = join(dirPath, a);
|
|
163
|
+
const bPath = join(dirPath, b);
|
|
164
|
+
try {
|
|
165
|
+
const aIsDir = statSync(aPath).isDirectory();
|
|
166
|
+
const bIsDir = statSync(bPath).isDirectory();
|
|
167
|
+
if (aIsDir !== bIsDir)
|
|
168
|
+
return aIsDir ? -1 : 1;
|
|
169
|
+
return a.localeCompare(b);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
entries.forEach((entry, index) => {
|
|
176
|
+
const isLast = index === entries.length - 1;
|
|
177
|
+
const entryPath = join(dirPath, entry);
|
|
178
|
+
let stats;
|
|
179
|
+
try {
|
|
180
|
+
stats = statSync(entryPath);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const isDirectory = stats.isDirectory();
|
|
186
|
+
const icon = getFileIcon(entry, isDirectory);
|
|
187
|
+
const color = getFileColor(entry, isDirectory);
|
|
188
|
+
// Build the tree branch characters
|
|
189
|
+
const branch = isLast ? '└── ' : '├── ';
|
|
190
|
+
const connector = isLast ? ' ' : '│ ';
|
|
191
|
+
// Build the line
|
|
192
|
+
let line = `${prefix}${branch}${icon} ${color(entry)}`;
|
|
193
|
+
// Add size info if requested
|
|
194
|
+
if (showSize && !isDirectory) {
|
|
195
|
+
line += ` ${c.dim(formatSize(stats.size))}`;
|
|
196
|
+
}
|
|
197
|
+
results.push(line);
|
|
198
|
+
// Recurse into directories
|
|
199
|
+
if (isDirectory) {
|
|
200
|
+
buildTree(entryPath, prefix + connector, { ...options, currentDepth: currentDepth + 1 }, results);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generate a visual file tree
|
|
206
|
+
*/
|
|
207
|
+
export function generateTree(rootPath, options = {}) {
|
|
208
|
+
if (!existsSync(rootPath)) {
|
|
209
|
+
return c.error(`Path not found: ${rootPath}`);
|
|
210
|
+
}
|
|
211
|
+
const stats = statSync(rootPath);
|
|
212
|
+
if (!stats.isDirectory()) {
|
|
213
|
+
return c.error(`Not a directory: ${rootPath}`);
|
|
214
|
+
}
|
|
215
|
+
const results = [];
|
|
216
|
+
const rootIcon = '📁';
|
|
217
|
+
const rootName = rootPath === '.' ? process.cwd().split('/').pop() || '.' : rootPath;
|
|
218
|
+
// Add root
|
|
219
|
+
results.push(`${rootIcon} ${c.primary.bold(rootName)}/`);
|
|
220
|
+
// Build tree
|
|
221
|
+
buildTree(rootPath, '', { ...options, currentDepth: 0 }, results);
|
|
222
|
+
// Add summary
|
|
223
|
+
const fileCount = results.length - 1; // Exclude root
|
|
224
|
+
results.push('');
|
|
225
|
+
results.push(c.muted(` ${fileCount} items shown`));
|
|
226
|
+
if ((options.currentDepth || 0) >= (options.maxDepth || 3)) {
|
|
227
|
+
results.push(c.muted(` (depth limit: ${options.maxDepth || 3})`));
|
|
228
|
+
}
|
|
229
|
+
return results.join('\n');
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Parse tree command arguments
|
|
233
|
+
*/
|
|
234
|
+
export function parseTreeArgs(args) {
|
|
235
|
+
const options = {
|
|
236
|
+
maxDepth: 3,
|
|
237
|
+
showHidden: false,
|
|
238
|
+
showSize: false,
|
|
239
|
+
exclude: [],
|
|
240
|
+
};
|
|
241
|
+
let path = '.';
|
|
242
|
+
for (let i = 0; i < args.length; i++) {
|
|
243
|
+
const arg = args[i];
|
|
244
|
+
if (arg === '-a' || arg === '--all') {
|
|
245
|
+
options.showHidden = true;
|
|
246
|
+
}
|
|
247
|
+
else if (arg === '-s' || arg === '--size') {
|
|
248
|
+
options.showSize = true;
|
|
249
|
+
}
|
|
250
|
+
else if (arg === '-d' || arg === '--depth') {
|
|
251
|
+
const depth = parseInt(args[i + 1], 10);
|
|
252
|
+
if (!isNaN(depth) && depth > 0) {
|
|
253
|
+
options.maxDepth = depth;
|
|
254
|
+
i++; // Skip next arg
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (arg.startsWith('-')) {
|
|
258
|
+
// Unknown flag, ignore
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
// Assume it's a path
|
|
262
|
+
path = arg;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return { path, options };
|
|
266
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ikie-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "Agentic coding CLI — your terminal AI pair programmer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"build": "tsc",
|
|
30
30
|
"dev": "tsx src/index.ts",
|
|
31
31
|
"start": "node dist/index.js",
|
|
32
|
+
"test": "node --import tsx --test src/agent.test.ts src/mcp-manager.test.ts src/skills.test.ts",
|
|
32
33
|
"prepublishOnly": "npm run build"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|