ai-devx 1.0.4 ā 1.0.5
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/bin/cli.js +12 -0
- package/package.json +1 -1
- package/src/commands/shell.js +349 -0
package/bin/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ const pkg = require("../package.json");
|
|
|
6
6
|
const initCommand = require("../src/commands/init");
|
|
7
7
|
const updateCommand = require("../src/commands/update");
|
|
8
8
|
const statusCommand = require("../src/commands/status");
|
|
9
|
+
const shellCommand = require("../src/commands/shell");
|
|
9
10
|
|
|
10
11
|
console.log(
|
|
11
12
|
chalk.cyan.bold(`
|
|
@@ -59,6 +60,13 @@ program
|
|
|
59
60
|
.option("-p, --path <path>", "Check specific directory", process.cwd())
|
|
60
61
|
.action(statusCommand);
|
|
61
62
|
|
|
63
|
+
program
|
|
64
|
+
.command("shell [path]")
|
|
65
|
+
.description(
|
|
66
|
+
"Start interactive shell to browse skills, agents, and workflows",
|
|
67
|
+
)
|
|
68
|
+
.action(shellCommand);
|
|
69
|
+
|
|
62
70
|
program.on("--help", () => {
|
|
63
71
|
console.log("");
|
|
64
72
|
console.log(chalk.bold("Examples:"));
|
|
@@ -77,6 +85,9 @@ program.on("--help", () => {
|
|
|
77
85
|
console.log(
|
|
78
86
|
" $ ai-devx init --assistant claude,gemini # Install with both assistants",
|
|
79
87
|
);
|
|
88
|
+
console.log(
|
|
89
|
+
" $ ai-devx shell # Start interactive shell",
|
|
90
|
+
);
|
|
80
91
|
console.log(" $ ai-devx update # Update templates");
|
|
81
92
|
console.log(
|
|
82
93
|
" $ ai-devx status # Check installation status",
|
|
@@ -84,6 +95,7 @@ program.on("--help", () => {
|
|
|
84
95
|
console.log("");
|
|
85
96
|
console.log(chalk.bold("Quick Start:"));
|
|
86
97
|
console.log(" $ npx ai-devx init");
|
|
98
|
+
console.log(" $ npx ai-devx shell");
|
|
87
99
|
console.log("");
|
|
88
100
|
});
|
|
89
101
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
const readline = require("readline");
|
|
5
|
+
|
|
6
|
+
class InteractiveCLI {
|
|
7
|
+
constructor(agentPath) {
|
|
8
|
+
this.agentPath = agentPath;
|
|
9
|
+
this.workflows = [];
|
|
10
|
+
this.skills = [];
|
|
11
|
+
this.agents = [];
|
|
12
|
+
this.scripts = [];
|
|
13
|
+
this.rules = [];
|
|
14
|
+
this.shared = [];
|
|
15
|
+
this.workflowsPath = path.join(agentPath, "workflows");
|
|
16
|
+
this.skillsPath = path.join(agentPath, "skills");
|
|
17
|
+
this.agentsPath = path.join(agentPath, "agents");
|
|
18
|
+
this.scriptsPath = path.join(agentPath, "scripts");
|
|
19
|
+
this.rulesPath = path.join(agentPath, "rules");
|
|
20
|
+
this.sharedPath = path.join(agentPath, ".shared");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async loadResources() {
|
|
24
|
+
// Load workflows
|
|
25
|
+
if (await fs.pathExists(this.workflowsPath)) {
|
|
26
|
+
const files = await fs.readdir(this.workflowsPath);
|
|
27
|
+
this.workflows = files
|
|
28
|
+
.filter((f) => f.endsWith(".md"))
|
|
29
|
+
.map((f) => ({
|
|
30
|
+
name: `/${path.basename(f, ".md")}`,
|
|
31
|
+
file: f,
|
|
32
|
+
type: "workflow",
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Load skills
|
|
37
|
+
if (await fs.pathExists(this.skillsPath)) {
|
|
38
|
+
const entries = await fs.readdir(this.skillsPath, {
|
|
39
|
+
withFileTypes: true,
|
|
40
|
+
});
|
|
41
|
+
this.skills = entries
|
|
42
|
+
.filter((e) => e.isDirectory())
|
|
43
|
+
.map((e) => ({
|
|
44
|
+
name: e.name,
|
|
45
|
+
path: path.join(this.skillsPath, e.name),
|
|
46
|
+
type: "skill",
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Load agents
|
|
51
|
+
if (await fs.pathExists(this.agentsPath)) {
|
|
52
|
+
const files = await fs.readdir(this.agentsPath);
|
|
53
|
+
this.agents = files
|
|
54
|
+
.filter((f) => f.endsWith(".md"))
|
|
55
|
+
.map((f) => ({
|
|
56
|
+
name: `@${path.basename(f, ".md")}`,
|
|
57
|
+
file: f,
|
|
58
|
+
type: "agent",
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Load scripts
|
|
63
|
+
if (await fs.pathExists(this.scriptsPath)) {
|
|
64
|
+
const files = await fs.readdir(this.scriptsPath);
|
|
65
|
+
this.scripts = files
|
|
66
|
+
.filter((f) => f.endsWith(".py"))
|
|
67
|
+
.map((f) => ({
|
|
68
|
+
name: f,
|
|
69
|
+
file: f,
|
|
70
|
+
type: "script",
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Load rules
|
|
75
|
+
if (await fs.pathExists(this.rulesPath)) {
|
|
76
|
+
const files = await fs.readdir(this.rulesPath);
|
|
77
|
+
this.rules = files
|
|
78
|
+
.filter((f) => f.endsWith(".md"))
|
|
79
|
+
.map((f) => ({
|
|
80
|
+
name: path.basename(f, ".md"),
|
|
81
|
+
file: f,
|
|
82
|
+
type: "rule",
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Load shared
|
|
87
|
+
if (await fs.pathExists(this.sharedPath)) {
|
|
88
|
+
const entries = await fs.readdir(this.sharedPath, {
|
|
89
|
+
withFileTypes: true,
|
|
90
|
+
});
|
|
91
|
+
this.shared = entries
|
|
92
|
+
.filter((e) => e.isDirectory())
|
|
93
|
+
.map((e) => ({
|
|
94
|
+
name: e.name,
|
|
95
|
+
path: path.join(this.sharedPath, e.name),
|
|
96
|
+
type: "shared",
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
showHelp() {
|
|
102
|
+
console.log(chalk.bold("\nš Available Commands:\n"));
|
|
103
|
+
|
|
104
|
+
console.log(chalk.yellow.bold("Slash Commands (Workflows):"));
|
|
105
|
+
this.workflows.forEach((w) => {
|
|
106
|
+
console.log(` ${chalk.cyan(w.name)} - Workflow command`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(chalk.yellow.bold("\nSkills:"));
|
|
110
|
+
this.skills.slice(0, 15).forEach((s) => {
|
|
111
|
+
console.log(` ${chalk.green(s.name)} - Domain knowledge module`);
|
|
112
|
+
});
|
|
113
|
+
if (this.skills.length > 15) {
|
|
114
|
+
console.log(` ${chalk.gray(`... and ${this.skills.length - 15} more`)}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log(chalk.yellow.bold("\nAgents:"));
|
|
118
|
+
this.agents.slice(0, 10).forEach((a) => {
|
|
119
|
+
console.log(` ${chalk.magenta(a.name)} - Specialist agent`);
|
|
120
|
+
});
|
|
121
|
+
if (this.agents.length > 10) {
|
|
122
|
+
console.log(` ${chalk.gray(`... and ${this.agents.length - 10} more`)}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(chalk.yellow.bold("\nScripts:"));
|
|
126
|
+
this.scripts.slice(0, 8).forEach((s) => {
|
|
127
|
+
console.log(` ${chalk.blue(s.name)} - Automation script`);
|
|
128
|
+
});
|
|
129
|
+
if (this.scripts.length > 8) {
|
|
130
|
+
console.log(` ${chalk.gray(`... and ${this.scripts.length - 8} more`)}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log(chalk.yellow.bold("\nRules:"));
|
|
134
|
+
this.rules.forEach((r) => {
|
|
135
|
+
console.log(` ${chalk.red(r.name)} - Assistant rules`);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (this.shared.length > 0) {
|
|
139
|
+
console.log(chalk.yellow.bold("\nShared Resources:"));
|
|
140
|
+
this.shared.forEach((s) => {
|
|
141
|
+
console.log(` ${chalk.gray(s.name)} - Shared utilities`);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(chalk.yellow.bold("\nOther Commands:"));
|
|
146
|
+
console.log(` ${chalk.cyan("/help")} - Show this menu`);
|
|
147
|
+
console.log(` ${chalk.cyan("/exit")} - Exit interactive mode`);
|
|
148
|
+
console.log(` ${chalk.cyan("clear")} - Clear screen`);
|
|
149
|
+
console.log();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async executeWorkflow(workflowName, args = "") {
|
|
153
|
+
const workflow = this.workflows.find((w) => w.name === workflowName);
|
|
154
|
+
if (!workflow) {
|
|
155
|
+
console.log(chalk.red(`ā Workflow '${workflowName}' not found`));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const workflowPath = path.join(this.workflowsPath, workflow.file);
|
|
160
|
+
try {
|
|
161
|
+
const content = await fs.readFile(workflowPath, "utf-8");
|
|
162
|
+
console.log(chalk.bold(`\nš Workflow: ${workflowName}\n`));
|
|
163
|
+
|
|
164
|
+
// Show first 50 lines or until first separator
|
|
165
|
+
const lines = content.split("\n");
|
|
166
|
+
const previewLines = [];
|
|
167
|
+
for (const line of lines) {
|
|
168
|
+
if (line.startsWith("---") && previewLines.length > 0) break;
|
|
169
|
+
previewLines.push(line);
|
|
170
|
+
if (previewLines.length >= 30) break;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log(previewLines.join("\n"));
|
|
174
|
+
console.log(chalk.gray("\n... (truncated)"));
|
|
175
|
+
console.log(chalk.yellow(`\nFull file: ${workflowPath}\n`));
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.log(chalk.red(`ā Error reading workflow: ${error.message}`));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async executeSkill(skillName) {
|
|
182
|
+
const skill = this.skills.find((s) => s.name === skillName);
|
|
183
|
+
if (!skill) {
|
|
184
|
+
console.log(chalk.red(`ā Skill '${skillName}' not found`));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const skillMdPath = path.join(skill.path, "SKILL.md");
|
|
189
|
+
try {
|
|
190
|
+
if (await fs.pathExists(skillMdPath)) {
|
|
191
|
+
const content = await fs.readFile(skillMdPath, "utf-8");
|
|
192
|
+
console.log(chalk.bold(`\nš Skill: ${skillName}\n`));
|
|
193
|
+
|
|
194
|
+
const lines = content.split("\n").slice(0, 40);
|
|
195
|
+
console.log(lines.join("\n"));
|
|
196
|
+
console.log(chalk.gray("\n... (truncated)"));
|
|
197
|
+
console.log(chalk.yellow(`\nFull file: ${skillMdPath}\n`));
|
|
198
|
+
} else {
|
|
199
|
+
console.log(chalk.bold(`\nš Skill: ${skillName}\n`));
|
|
200
|
+
console.log(`Path: ${skill.path}`);
|
|
201
|
+
|
|
202
|
+
const files = await fs.readdir(skill.path);
|
|
203
|
+
console.log("\nContents:");
|
|
204
|
+
files.forEach((f) => console.log(` - ${f}`));
|
|
205
|
+
console.log();
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.log(chalk.red(`ā Error reading skill: ${error.message}`));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async executeAgent(agentName) {
|
|
213
|
+
const agent = this.agents.find((a) => a.name === agentName);
|
|
214
|
+
if (!agent) {
|
|
215
|
+
console.log(chalk.red(`ā Agent '${agentName}' not found`));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const agentPath = path.join(this.agentsPath, agent.file);
|
|
220
|
+
try {
|
|
221
|
+
const content = await fs.readFile(agentPath, "utf-8");
|
|
222
|
+
console.log(chalk.bold(`\nš¤ Agent: ${agentName}\n`));
|
|
223
|
+
|
|
224
|
+
const lines = content.split("\n").slice(0, 40);
|
|
225
|
+
console.log(lines.join("\n"));
|
|
226
|
+
console.log(chalk.gray("\n... (truncated)"));
|
|
227
|
+
console.log(chalk.yellow(`\nFull file: ${agentPath}\n`));
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.log(chalk.red(`ā Error reading agent: ${error.message}`));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async executeRule(ruleName) {
|
|
234
|
+
const rule = this.rules.find((r) => r.name === ruleName);
|
|
235
|
+
if (!rule) {
|
|
236
|
+
console.log(chalk.red(`ā Rule '${ruleName}' not found`));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const rulePath = path.join(this.rulesPath, rule.file);
|
|
241
|
+
try {
|
|
242
|
+
const content = await fs.readFile(rulePath, "utf-8");
|
|
243
|
+
console.log(chalk.bold(`\nš Rule: ${ruleName}\n`));
|
|
244
|
+
|
|
245
|
+
const lines = content.split("\n").slice(0, 40);
|
|
246
|
+
console.log(lines.join("\n"));
|
|
247
|
+
console.log(chalk.gray("\n... (truncated)"));
|
|
248
|
+
console.log(chalk.yellow(`\nFull file: ${rulePath}\n`));
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.log(chalk.red(`ā Error reading rule: ${error.message}`));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async start() {
|
|
255
|
+
await this.loadResources();
|
|
256
|
+
|
|
257
|
+
console.log(
|
|
258
|
+
chalk.cyan.bold(`
|
|
259
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
260
|
+
ā š¤ AI-DEVX Interactive Shell ā
|
|
261
|
+
ā Type / to see all commands and resources ā
|
|
262
|
+
ā Type /help for help or /exit to quit ā
|
|
263
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
264
|
+
`),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const rl = readline.createInterface({
|
|
268
|
+
input: process.stdin,
|
|
269
|
+
output: process.stdout,
|
|
270
|
+
prompt: chalk.cyan("ai-devx> "),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
rl.prompt();
|
|
274
|
+
|
|
275
|
+
rl.on("line", async (line) => {
|
|
276
|
+
const input = line.trim();
|
|
277
|
+
|
|
278
|
+
if (input === "/exit" || input === "exit" || input === "quit") {
|
|
279
|
+
console.log(chalk.yellow("š Goodbye!"));
|
|
280
|
+
rl.close();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (input === "" || input === "/") {
|
|
285
|
+
this.showHelp();
|
|
286
|
+
} else if (input === "/help" || input === "help") {
|
|
287
|
+
console.log(chalk.bold("\nšÆ Quick Guide:\n"));
|
|
288
|
+
console.log("Type any of the following:");
|
|
289
|
+
console.log(
|
|
290
|
+
` ${chalk.cyan("/")} - Show all available commands and resources`,
|
|
291
|
+
);
|
|
292
|
+
console.log(
|
|
293
|
+
` ${chalk.cyan("/<workflow>")} - View workflow details (e.g., /plan)`,
|
|
294
|
+
);
|
|
295
|
+
console.log(
|
|
296
|
+
` ${chalk.cyan("@<agent>")} - View agent details (e.g., @orchestrator)`,
|
|
297
|
+
);
|
|
298
|
+
console.log(
|
|
299
|
+
` ${chalk.cyan("<skill-name>")} - View skill details (e.g., clean-code)`,
|
|
300
|
+
);
|
|
301
|
+
console.log(
|
|
302
|
+
` ${chalk.cyan("<rule-name>")} - View rule details (e.g., CLAUDE)`,
|
|
303
|
+
);
|
|
304
|
+
console.log(` ${chalk.cyan("clear")} - Clear the screen`);
|
|
305
|
+
console.log(` ${chalk.cyan("/exit")} - Exit interactive mode\n`);
|
|
306
|
+
} else if (input === "clear") {
|
|
307
|
+
console.clear();
|
|
308
|
+
} else if (input.startsWith("/")) {
|
|
309
|
+
// Workflow command
|
|
310
|
+
await this.executeWorkflow(input);
|
|
311
|
+
} else if (input.startsWith("@")) {
|
|
312
|
+
// Agent command
|
|
313
|
+
await this.executeAgent(input);
|
|
314
|
+
} else if (this.skills.find((s) => s.name === input)) {
|
|
315
|
+
// Skill command
|
|
316
|
+
await this.executeSkill(input);
|
|
317
|
+
} else if (this.rules.find((r) => r.name === input)) {
|
|
318
|
+
// Rule command
|
|
319
|
+
await this.executeRule(input);
|
|
320
|
+
} else {
|
|
321
|
+
console.log(chalk.yellow(`ā ļø Unknown command: ${input}`));
|
|
322
|
+
console.log(chalk.gray("Type / to see available commands\n"));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
rl.prompt();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
rl.on("close", () => {
|
|
329
|
+
console.log(chalk.yellow("\nš Goodbye!"));
|
|
330
|
+
process.exit(0);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function shellCommand(targetPath) {
|
|
336
|
+
const cwd = targetPath || process.cwd();
|
|
337
|
+
const agentPath = path.join(path.resolve(cwd), ".agent");
|
|
338
|
+
|
|
339
|
+
if (!(await fs.pathExists(agentPath))) {
|
|
340
|
+
console.log(chalk.red(`ā AI-DEVX not installed in ${cwd}`));
|
|
341
|
+
console.log(chalk.yellow("Run: npx ai-devx init"));
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const cli = new InteractiveCLI(agentPath);
|
|
346
|
+
await cli.start();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
module.exports = shellCommand;
|