shellwise 0.2.6 → 0.2.7
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 +3 -1
- package/package.json +1 -1
- package/src/cli/search.ts +11 -8
- package/src/db/queries.ts +10 -0
- package/src/index.ts +32 -6
package/README.md
CHANGED
|
@@ -103,12 +103,14 @@ Both `shellwise` and `sw` work as the command name:
|
|
|
103
103
|
```bash
|
|
104
104
|
shellwise search [--query <text>] # Interactive fuzzy search (Ctrl+R)
|
|
105
105
|
shellwise suggest --query <text> # Get top suggestion (used by shell hook)
|
|
106
|
-
shellwise add
|
|
106
|
+
shellwise add <cmd> # Save a command to history
|
|
107
|
+
shellwise delete [query] # Interactive search & delete a command
|
|
107
108
|
shellwise init <zsh|bash> # Output shell integration script
|
|
108
109
|
shellwise import [zsh|bash] # Import existing shell history
|
|
109
110
|
shellwise stats # Show usage statistics
|
|
110
111
|
shellwise prune --days <n> # Remove entries older than n days
|
|
111
112
|
shellwise daemon start|stop|status # Manage background daemon
|
|
113
|
+
shellwise version # Show current version
|
|
112
114
|
```
|
|
113
115
|
|
|
114
116
|
### Import existing history
|
package/package.json
CHANGED
package/src/cli/search.ts
CHANGED
|
@@ -25,7 +25,7 @@ interface SearchState {
|
|
|
25
25
|
renderedLines: number;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function
|
|
28
|
+
export function pickCommand(initialQuery: string = ""): string | null {
|
|
29
29
|
const cwd = process.env.PWD || process.cwd();
|
|
30
30
|
|
|
31
31
|
const state: SearchState = {
|
|
@@ -78,22 +78,18 @@ export function runSearch(initialQuery: string = ""): void {
|
|
|
78
78
|
|
|
79
79
|
if (key.type === "special" && key.key === "escape") {
|
|
80
80
|
cleanup();
|
|
81
|
-
return;
|
|
81
|
+
return null;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
if (key.type === "ctrl" && key.char === "c") {
|
|
85
85
|
cleanup();
|
|
86
|
-
return;
|
|
86
|
+
return null;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
if (key.type === "special" && key.key === "enter") {
|
|
90
90
|
const selected = state.results[state.selectedIndex];
|
|
91
91
|
cleanup();
|
|
92
|
-
|
|
93
|
-
// Output to stdout (fd 1) for shell to capture
|
|
94
|
-
writeSync(1, selected.command);
|
|
95
|
-
}
|
|
96
|
-
return;
|
|
92
|
+
return selected?.command ?? null;
|
|
97
93
|
}
|
|
98
94
|
|
|
99
95
|
let needsSearch = false;
|
|
@@ -197,6 +193,13 @@ export function runSearch(initialQuery: string = ""): void {
|
|
|
197
193
|
}
|
|
198
194
|
}
|
|
199
195
|
|
|
196
|
+
export function runSearch(initialQuery: string = ""): void {
|
|
197
|
+
const selected = pickCommand(initialQuery);
|
|
198
|
+
if (selected) {
|
|
199
|
+
writeSync(1, selected);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
200
203
|
function getVisibleCount(): number {
|
|
201
204
|
const { rows } = getTerminalSize();
|
|
202
205
|
return Math.min(Math.max(rows - 4, 3), 15); // 3 minimum, 15 max
|
package/src/db/queries.ts
CHANGED
|
@@ -166,6 +166,16 @@ export function pruneOlderThan(days: number): number {
|
|
|
166
166
|
return result.changes;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
export function deleteCommand(command: string): boolean {
|
|
170
|
+
const db = getDb();
|
|
171
|
+
const hash = hashCommand(command);
|
|
172
|
+
|
|
173
|
+
const result = db.run("DELETE FROM commands WHERE command_hash = ?", [hash]);
|
|
174
|
+
db.run("DELETE FROM command_stats WHERE command_hash = ?", [hash]);
|
|
175
|
+
|
|
176
|
+
return result.changes > 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
export function getExistingHashes(): Set<string> {
|
|
170
180
|
const db = getDb();
|
|
171
181
|
const rows = db
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import { runAdd } from "./cli/add";
|
|
4
|
-
import { runSearch } from "./cli/search";
|
|
4
|
+
import { runSearch, pickCommand } from "./cli/search";
|
|
5
5
|
import { runSuggest } from "./cli/suggest";
|
|
6
6
|
import { runInit } from "./cli/init";
|
|
7
7
|
import { runImport } from "./cli/import";
|
|
8
8
|
import { runStats } from "./cli/stats";
|
|
9
9
|
import { runPrune } from "./cli/prune";
|
|
10
|
+
import { deleteCommand } from "./db/queries";
|
|
10
11
|
import { closeDb } from "./db/connection";
|
|
11
12
|
import { startServer, isDaemonRunning, getDaemonInfo } from "./daemon/server";
|
|
12
13
|
import { daemonRequest } from "./daemon/client";
|
|
@@ -34,12 +35,14 @@ Usage: shellwise <command> [options] (or: sw <command>)
|
|
|
34
35
|
Commands:
|
|
35
36
|
search [--query <text>] Interactive fuzzy search (Ctrl+R)
|
|
36
37
|
suggest --query <text> Get top suggestion (used by shell hook)
|
|
37
|
-
add
|
|
38
|
+
add <cmd> Save a command to history
|
|
39
|
+
delete <cmd> Delete a command from history
|
|
38
40
|
init <zsh|bash> Output shell integration script
|
|
39
41
|
import [zsh|bash] Import existing shell history
|
|
40
42
|
stats Show usage statistics
|
|
41
43
|
prune --days <n> Remove entries older than n days
|
|
42
44
|
daemon start|stop|status Manage background daemon (faster suggest)
|
|
45
|
+
version Show current version
|
|
43
46
|
|
|
44
47
|
Setup:
|
|
45
48
|
Add to ~/.zshrc: eval "$(shellwise init zsh)"
|
|
@@ -79,20 +82,21 @@ async function main(): Promise<void> {
|
|
|
79
82
|
|
|
80
83
|
case "add": {
|
|
81
84
|
const flags = parseFlags(args.slice(1));
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
const addCmd = flags.command || args.slice(1).filter(a => !a.startsWith("--")).join(" ");
|
|
86
|
+
if (!addCmd) {
|
|
87
|
+
console.error("Usage: shellwise add <cmd>");
|
|
84
88
|
process.exit(1);
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
// Try daemon first
|
|
88
92
|
// Strip tabs from command to avoid breaking protocol delimiter
|
|
89
|
-
const safeCommand =
|
|
93
|
+
const safeCommand = addCmd.replace(/\t/g, " ");
|
|
90
94
|
const addMsg = `ADD\t${safeCommand}\t${flags.cwd || ""}\t${flags["exit-code"] || "0"}\t${flags.duration || "0"}\t${flags.session || ""}\t${flags.shell || ""}\n`;
|
|
91
95
|
const addResult = await daemonRequest(addMsg);
|
|
92
96
|
if (!addResult) {
|
|
93
97
|
// Fallback: direct
|
|
94
98
|
runAdd({
|
|
95
|
-
command:
|
|
99
|
+
command: addCmd,
|
|
96
100
|
cwd: flags.cwd,
|
|
97
101
|
exitCode: flags["exit-code"] ? parseInt(flags["exit-code"]) : undefined,
|
|
98
102
|
duration: flags.duration ? parseInt(flags.duration) : undefined,
|
|
@@ -185,6 +189,28 @@ async function main(): Promise<void> {
|
|
|
185
189
|
break;
|
|
186
190
|
}
|
|
187
191
|
|
|
192
|
+
case "delete": {
|
|
193
|
+
const delQuery = args.slice(1).join(" ");
|
|
194
|
+
const delCmd = pickCommand(delQuery);
|
|
195
|
+
if (delCmd) {
|
|
196
|
+
const deleted = deleteCommand(delCmd);
|
|
197
|
+
if (deleted) {
|
|
198
|
+
console.log(`Deleted: ${delCmd}`);
|
|
199
|
+
} else {
|
|
200
|
+
console.log("Command not found in history.");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case "version":
|
|
207
|
+
case "--version":
|
|
208
|
+
case "-v": {
|
|
209
|
+
const pkg = require("../package.json");
|
|
210
|
+
console.log(pkg.version);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
|
|
188
214
|
case "help":
|
|
189
215
|
case "--help":
|
|
190
216
|
case "-h":
|