caroushell 0.1.18 → 0.1.20

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.
@@ -171,8 +171,9 @@ class AISuggester {
171
171
  descriptions.push(desc);
172
172
  }
173
173
  }
174
- const prompt = `You are a shell assistant. Given a partial shell input, suggest ${maxDisplayed}\
175
- useful, concise shell commands that the user might run next.\
174
+ const prompt = `You are a shell assistant. Given a partial shell input, \
175
+ suggest ${maxDisplayed} useful, concise shell commands that the user might run \
176
+ next.
176
177
  Return one suggestion per line, no numbering, no extra text.
177
178
  Return the whole suggestion, not just what remains to type out.
178
179
 
@@ -193,7 +194,7 @@ ${descriptions.join("\n\n")}
193
194
  .map((s) => s.trim())
194
195
  .filter(Boolean)
195
196
  .slice(0, maxDisplayed);
196
- (0, logs_1.logLine)(`AI lines: ${lines.length}`);
197
+ (0, logs_1.logLine)(`AI lines: ${lines}`);
197
198
  return lines;
198
199
  }
199
200
  }
package/dist/app.js CHANGED
@@ -8,14 +8,16 @@ const history_suggester_1 = require("./history-suggester");
8
8
  const ai_suggester_1 = require("./ai-suggester");
9
9
  const file_suggester_1 = require("./file-suggester");
10
10
  const spawner_1 = require("./spawner");
11
+ const logs_1 = require("./logs");
11
12
  class App {
12
- constructor() {
13
+ constructor(deps = {}) {
13
14
  this.usingFileSuggestions = false;
14
- this.terminal = new terminal_1.Terminal();
15
- this.keyboard = new keyboard_1.Keyboard();
16
- this.history = new history_suggester_1.HistorySuggester();
17
- this.ai = new ai_suggester_1.AISuggester();
18
- this.files = new file_suggester_1.FileSuggester();
15
+ this.terminal = deps.terminal ?? new terminal_1.Terminal();
16
+ this.keyboard = deps.keyboard ?? new keyboard_1.Keyboard();
17
+ this.history = deps.topPanel ?? new history_suggester_1.HistorySuggester();
18
+ this.ai = deps.bottomPanel ?? new ai_suggester_1.AISuggester();
19
+ this.files = deps.files ?? new file_suggester_1.FileSuggester();
20
+ this.suggesters = deps.suggesters ?? [this.history, this.ai, this.files];
19
21
  this.carousel = new carousel_1.Carousel({
20
22
  top: this.history,
21
23
  bottom: this.ai,
@@ -170,7 +172,7 @@ class App {
170
172
  try {
171
173
  const storeInHistory = await (0, spawner_1.runUserCommand)(cmd);
172
174
  if (storeInHistory) {
173
- await this.history.add(cmd);
175
+ await this.broadcastCommand(cmd);
174
176
  }
175
177
  }
176
178
  finally {
@@ -242,5 +244,18 @@ class App {
242
244
  this.usingFileSuggestions = true;
243
245
  this.carousel.setTopSuggester(this.files);
244
246
  }
247
+ async broadcastCommand(cmd) {
248
+ const listeners = this.suggesters
249
+ .map((suggester) => suggester.onCommandRan?.(cmd))
250
+ .filter(Boolean);
251
+ if (listeners.length === 0)
252
+ return;
253
+ try {
254
+ await Promise.all(listeners);
255
+ }
256
+ catch (err) {
257
+ (0, logs_1.logLine)("suggester onCommandRan error: " + err?.message);
258
+ }
259
+ }
245
260
  }
246
261
  exports.App = App;
@@ -10,6 +10,7 @@ const config_1 = require("./config");
10
10
  class HistorySuggester {
11
11
  constructor(filePath) {
12
12
  this.prefix = "⌛";
13
+ // `items` is the history as a list of commands, with the most recent at index 0
13
14
  this.items = [];
14
15
  this.filteredItems = [];
15
16
  this.maxItems = 1000;
@@ -47,6 +48,9 @@ class HistorySuggester {
47
48
  .catch(() => { });
48
49
  await fs_1.promises.appendFile(this.filePath, this.serializeHistoryEntry(command), "utf8");
49
50
  }
51
+ async onCommandRan(command) {
52
+ await this.add(command);
53
+ }
50
54
  latest() {
51
55
  return this.filteredItems;
52
56
  }
@@ -71,18 +75,19 @@ class HistorySuggester {
71
75
  carousel.render();
72
76
  }
73
77
  descriptionForAi() {
78
+ // This goes into the prompt
74
79
  const lines = [];
75
80
  const maxHistoryLines = 20;
76
- const start = Math.max(0, this.items.length - maxHistoryLines);
77
- const end = this.items.length - 1;
78
- const reverseSlice = this.items.slice(start, end).reverse();
79
- if (reverseSlice.length > 0) {
80
- lines.push(`The most recent command is: "${reverseSlice[0]}"`);
81
+ const start = 0;
82
+ const end = maxHistoryLines;
83
+ const newToOldSlice = this.items.slice(start, end);
84
+ if (newToOldSlice.length > 0) {
85
+ lines.push(`The most recent command is: "${newToOldSlice[0]}"`);
81
86
  }
82
- if (reverseSlice.length > 1) {
87
+ if (newToOldSlice.length > 1) {
83
88
  lines.push("The most recent commands are (from recent to oldest):");
84
- for (let i = 0; i < reverseSlice.length; i++) {
85
- lines.push(` ${i + 1}. ${reverseSlice[i]}`);
89
+ for (let i = 0; i < newToOldSlice.length; i++) {
90
+ lines.push(` ${i + 1}. ${newToOldSlice[i]}`);
86
91
  }
87
92
  }
88
93
  return lines.join("\n");
package/dist/keyboard.js CHANGED
@@ -48,12 +48,12 @@ for (const seq of Object.keys(KEYMAP)) {
48
48
  }
49
49
  }
50
50
  class Keyboard extends events_1.EventEmitter {
51
- constructor() {
52
- super(...arguments);
51
+ constructor(stdin = process.stdin) {
52
+ super();
53
53
  this.capturing = false;
54
54
  this.buffer = '';
55
- this.stdin = process.stdin;
56
55
  this.onData = (data) => this.handleData(data);
56
+ this.stdin = stdin;
57
57
  }
58
58
  enableCapture() {
59
59
  if (this.capturing)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caroushell",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Terminal carousel that suggests commands from history, config, and AI.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/main.js",
@@ -17,6 +17,7 @@
17
17
  "build": "tsc -p tsconfig.release.json",
18
18
  "prepare": "npm run build",
19
19
  "start": "node dist/main.js",
20
+ "test": "node --import tsx --test tests/*.ts",
20
21
  "test:generate": "tsx src/test-generate.ts",
21
22
  "lint": "eslint . --ext .ts",
22
23
  "release": "tsx scripts/release.ts"