@seberto/agcp 1.0.1 → 1.0.2
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/agcp.js +17 -2
- package/package.json +1 -1
- package/service/ollama.js +52 -2
package/bin/agcp.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Command } from "commander";
|
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { confirm } from "@inquirer/prompts";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import generateCommand from "../service/ollama.js";
|
|
7
|
+
import generateCommand, { isSafe } from "../service/ollama.js";
|
|
8
8
|
|
|
9
9
|
const program = new Command();
|
|
10
10
|
|
|
@@ -19,6 +19,16 @@ program
|
|
|
19
19
|
|
|
20
20
|
const command = await generateCommand(prompt);
|
|
21
21
|
|
|
22
|
+
if (command === "UNSAFE") {
|
|
23
|
+
console.log(chalk.red("\n✖ That request is not development related or is unsafe. Only dev commands are supported."));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!isSafe(command)) {
|
|
28
|
+
console.log(chalk.red(`\n✖ Blocked unsafe command: ${chalk.bold(command)}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
console.log(chalk.cyan(`\n💡 Suggested command:\n ${chalk.bold(command)}\n`));
|
|
23
33
|
|
|
24
34
|
const shouldRun = await confirm({
|
|
@@ -28,7 +38,12 @@ program
|
|
|
28
38
|
|
|
29
39
|
if (shouldRun) {
|
|
30
40
|
console.log(chalk.green("\n▶ Running...\n"));
|
|
31
|
-
|
|
41
|
+
try {
|
|
42
|
+
execSync(command, { stdio: "inherit", shell: true });
|
|
43
|
+
} catch {
|
|
44
|
+
// command already printed its output, non-zero exit is not our error
|
|
45
|
+
}
|
|
46
|
+
|
|
32
47
|
} else {
|
|
33
48
|
console.log(chalk.gray("\nAborted."));
|
|
34
49
|
}
|
package/package.json
CHANGED
package/service/ollama.js
CHANGED
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
+
import { platform } from "os";
|
|
3
|
+
|
|
4
|
+
const OS_MAP = { darwin: "macOS", linux: "Linux", win32: "Windows" };
|
|
5
|
+
const os = OS_MAP[platform()] ?? platform();
|
|
6
|
+
const shell = platform() === "win32" ? "PowerShell" : "bash";
|
|
7
|
+
|
|
8
|
+
// Commands that are never allowed to run
|
|
9
|
+
const BLOCKED = [
|
|
10
|
+
/rm\s+-rf/,
|
|
11
|
+
/rm\s+-fr/,
|
|
12
|
+
/rmdir/,
|
|
13
|
+
/mkfs/,
|
|
14
|
+
/dd\s+if=/,
|
|
15
|
+
/:\(\)\{.*\}/, // fork bomb
|
|
16
|
+
/chmod\s+-R\s+777/,
|
|
17
|
+
/chown\s+-R/,
|
|
18
|
+
/shutdown/,
|
|
19
|
+
/reboot/,
|
|
20
|
+
/halt/,
|
|
21
|
+
/curl.*\|\s*sh/, // curl pipe to shell
|
|
22
|
+
/wget.*\|\s*sh/,
|
|
23
|
+
/sudo\s+rm/,
|
|
24
|
+
/>\s*\/dev\//, // writing to devices
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export function isSafe(command) {
|
|
28
|
+
return !BLOCKED.some((pattern) => pattern.test(command));
|
|
29
|
+
}
|
|
2
30
|
|
|
3
31
|
async function generateCommand(userPrompt) {
|
|
4
32
|
const { data } = await axios.get("http://localhost:11434/api/tags");
|
|
@@ -6,7 +34,19 @@ async function generateCommand(userPrompt) {
|
|
|
6
34
|
|
|
7
35
|
if (!model) throw new Error("No Ollama models found. Run 'ollama pull <model>' first.");
|
|
8
36
|
|
|
9
|
-
const prompt = `
|
|
37
|
+
const prompt = `You are a development shell command assistant for ${os} using ${shell}.
|
|
38
|
+
|
|
39
|
+
Allowed topics: git, npm, yarn, node, file navigation, code editors, docker, build tools, package managers, and general software development tasks.
|
|
40
|
+
|
|
41
|
+
Rules:
|
|
42
|
+
- Output a single shell command only
|
|
43
|
+
- No markdown, no backticks, no code blocks, no explanation
|
|
44
|
+
- One line only
|
|
45
|
+
- Only generate commands related to software development
|
|
46
|
+
- Never generate destructive commands like rm -rf, shutdown, reboot, mkfs, dd, fork bombs, or piping curl/wget to shell
|
|
47
|
+
- If the request is not development related, respond with exactly: UNSAFE
|
|
48
|
+
|
|
49
|
+
User request: ${userPrompt}`;
|
|
10
50
|
|
|
11
51
|
const response = await axios.post("http://localhost:11434/api/generate", {
|
|
12
52
|
model,
|
|
@@ -14,7 +54,17 @@ async function generateCommand(userPrompt) {
|
|
|
14
54
|
stream: false,
|
|
15
55
|
});
|
|
16
56
|
|
|
17
|
-
|
|
57
|
+
const raw = response.data.response.trim();
|
|
58
|
+
|
|
59
|
+
// Strip accidental markdown the model may add
|
|
60
|
+
const cleaned = raw
|
|
61
|
+
.replace(/^```[\w]*\n?/m, "")
|
|
62
|
+
.replace(/```$/m, "")
|
|
63
|
+
.replace(/^`|`$/g, "")
|
|
64
|
+
.split("\n")[0]
|
|
65
|
+
.trim();
|
|
66
|
+
|
|
67
|
+
return cleaned;
|
|
18
68
|
}
|
|
19
69
|
|
|
20
70
|
export default generateCommand;
|