caroushell 0.1.20 → 0.1.21
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 +4 -6
- package/dist/app.js +1 -0
- package/dist/spawner.js +83 -0
- package/dist/terminal.js +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/caroushell)
|
|
4
4
|
[](https://www.npmjs.com/package/caroushell)
|
|
5
5
|
|
|
6
|
-
Caroushell is
|
|
7
|
-
|
|
6
|
+
Caroushell is kind of like `bash` but you see history and AI suggestions as you
|
|
7
|
+
type.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -12,9 +12,6 @@ history, and AI suggestions as you type.
|
|
|
12
12
|
- The bottom panel of the carousel shows AI-generated command suggestions.
|
|
13
13
|
- Go up and down the carousel with arrow keys.
|
|
14
14
|
- Press `Enter` to run the highlighted command.
|
|
15
|
-
- Logs activity under `~/.caroushell/logs` for easy troubleshooting.
|
|
16
|
-
- Extensible config file (`~/.caroushell/config.toml`) so you can point the CLI
|
|
17
|
-
at different AI providers.
|
|
18
15
|
|
|
19
16
|
## UI
|
|
20
17
|
|
|
@@ -42,12 +39,13 @@ It would look like this:
|
|
|
42
39
|
|
|
43
40
|

|
|
44
41
|
|
|
45
|
-
##
|
|
42
|
+
## Setup
|
|
46
43
|
|
|
47
44
|
- Node.js 18 or newer.
|
|
48
45
|
- On first launch Caroushell will prompt you for an OpenAI-compatible endpoint
|
|
49
46
|
URL, API key, and model name, then store them in `~/.caroushell/config.toml`.
|
|
50
47
|
- You can also create the file manually:
|
|
48
|
+
- Logs are at `~/.caroushell/logs` for easy troubleshooting.
|
|
51
49
|
|
|
52
50
|
```toml
|
|
53
51
|
apiUrl = "https://openrouter.ai/api/v1"
|
package/dist/app.js
CHANGED
package/dist/spawner.js
CHANGED
|
@@ -7,6 +7,18 @@ const logs_1 = require("./logs");
|
|
|
7
7
|
const isWin = process.platform === "win32";
|
|
8
8
|
const shellBinary = isWin ? "cmd.exe" : "/bin/bash";
|
|
9
9
|
const shellArgs = isWin ? ["/d", "/s", "/c"] : ["-lc"];
|
|
10
|
+
const dirStack = [];
|
|
11
|
+
// Track last-known cwd per drive so `E:` switches like cmd.exe
|
|
12
|
+
// into the folder you were in before switching drives.
|
|
13
|
+
const driveCwds = {};
|
|
14
|
+
function updateDriveCwd(cwd = process.cwd()) {
|
|
15
|
+
if (!isWin)
|
|
16
|
+
return;
|
|
17
|
+
const drive = cwd.slice(0, 2).toUpperCase();
|
|
18
|
+
if (/^[A-Z]:$/.test(drive)) {
|
|
19
|
+
driveCwds[drive] = cwd;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
10
22
|
const builtInCommands = {
|
|
11
23
|
cd: async (args) => {
|
|
12
24
|
if (args.length === 1) {
|
|
@@ -16,6 +28,7 @@ const builtInCommands = {
|
|
|
16
28
|
const dest = expandVars(args[1]);
|
|
17
29
|
try {
|
|
18
30
|
process.chdir(dest);
|
|
31
|
+
updateDriveCwd();
|
|
19
32
|
}
|
|
20
33
|
catch (err) {
|
|
21
34
|
process.stderr.write(`cd: ${err.message}\n`);
|
|
@@ -23,11 +36,66 @@ const builtInCommands = {
|
|
|
23
36
|
}
|
|
24
37
|
return true;
|
|
25
38
|
},
|
|
39
|
+
pushd: async (args) => {
|
|
40
|
+
const current = process.cwd();
|
|
41
|
+
if (args.length === 1) {
|
|
42
|
+
const next = dirStack.shift();
|
|
43
|
+
if (!next) {
|
|
44
|
+
process.stderr.write("pushd: no other directory\n");
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
dirStack.unshift(current);
|
|
48
|
+
try {
|
|
49
|
+
process.chdir(next);
|
|
50
|
+
updateDriveCwd();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
process.stderr.write(`pushd: ${err.message}\n`);
|
|
54
|
+
dirStack.shift();
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
writeDirStack();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
const dest = expandVars(args[1]);
|
|
61
|
+
try {
|
|
62
|
+
process.chdir(dest);
|
|
63
|
+
updateDriveCwd();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
process.stderr.write(`pushd: ${err.message}\n`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
dirStack.unshift(current);
|
|
70
|
+
writeDirStack();
|
|
71
|
+
return true;
|
|
72
|
+
},
|
|
73
|
+
popd: async () => {
|
|
74
|
+
const next = dirStack.shift();
|
|
75
|
+
if (!next) {
|
|
76
|
+
process.stderr.write("popd: directory stack empty\n");
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
process.chdir(next);
|
|
81
|
+
updateDriveCwd();
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
process.stderr.write(`popd: ${err.message}\n`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
writeDirStack();
|
|
88
|
+
return true;
|
|
89
|
+
},
|
|
26
90
|
exit: async () => {
|
|
27
91
|
(0, process_1.exit)(0);
|
|
28
92
|
return false;
|
|
29
93
|
},
|
|
30
94
|
};
|
|
95
|
+
function writeDirStack() {
|
|
96
|
+
const parts = [process.cwd(), ...dirStack];
|
|
97
|
+
process.stdout.write(parts.join(" ") + "\n");
|
|
98
|
+
}
|
|
31
99
|
function expandVars(input) {
|
|
32
100
|
let out = input;
|
|
33
101
|
if (isWin) {
|
|
@@ -52,6 +120,20 @@ async function runUserCommand(command) {
|
|
|
52
120
|
const trimmed = command.trim();
|
|
53
121
|
if (!trimmed)
|
|
54
122
|
return false;
|
|
123
|
+
if (isWin && /^[a-zA-Z]:$/.test(trimmed)) {
|
|
124
|
+
// Windows drive switch (eg "E:") should restore that drive's last cwd.
|
|
125
|
+
const drive = trimmed.toUpperCase();
|
|
126
|
+
const target = driveCwds[drive] ?? `${drive}\\`;
|
|
127
|
+
try {
|
|
128
|
+
process.chdir(target);
|
|
129
|
+
updateDriveCwd();
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
process.stderr.write(`${trimmed}: ${err.message}\n`);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
55
137
|
const args = command.split(/\s+/);
|
|
56
138
|
if (typeof args[0] === "string" && builtInCommands[args[0]]) {
|
|
57
139
|
return await builtInCommands[args[0]](args);
|
|
@@ -70,3 +152,4 @@ async function runUserCommand(command) {
|
|
|
70
152
|
// many times until we fix it.
|
|
71
153
|
return true;
|
|
72
154
|
}
|
|
155
|
+
updateDriveCwd();
|
package/dist/terminal.js
CHANGED
|
@@ -29,6 +29,13 @@ class Terminal {
|
|
|
29
29
|
enableWrites() {
|
|
30
30
|
this.writesDisabled = false;
|
|
31
31
|
}
|
|
32
|
+
reset() {
|
|
33
|
+
// Some apps (such as vim) change the terminal cursor mode.
|
|
34
|
+
// We need to reset it to the default. To avoid arrow keys causing this:
|
|
35
|
+
// $> OAOBOCODODODODOAOAOCOB
|
|
36
|
+
const RESET_CURSOR_MODE = "\x1b[?1l";
|
|
37
|
+
this.write(RESET_CURSOR_MODE);
|
|
38
|
+
}
|
|
32
39
|
canWrite() {
|
|
33
40
|
return !this.writesDisabled;
|
|
34
41
|
}
|