shellwise 0.2.5 → 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 +28 -4
- package/package.json +1 -1
- package/src/cli/add.ts +1 -6
- package/src/cli/search.ts +11 -8
- package/src/daemon/server.ts +0 -4
- package/src/db/queries.ts +10 -0
- package/src/index.ts +32 -6
- package/src/utils/constants.ts +0 -1
package/README.md
CHANGED
|
@@ -34,10 +34,13 @@ Tab/Shift+Tab to navigate, Enter to select, Esc to dismiss
|
|
|
34
34
|
> **Important:** This is a CLI tool — install it **globally**.
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
#
|
|
37
|
+
# Homebrew
|
|
38
|
+
brew install kurovu146/tap/shellwise
|
|
39
|
+
|
|
40
|
+
# Bun
|
|
38
41
|
bun install -g shellwise
|
|
39
42
|
|
|
40
|
-
#
|
|
43
|
+
# npm
|
|
41
44
|
npm install -g shellwise
|
|
42
45
|
```
|
|
43
46
|
|
|
@@ -55,6 +58,19 @@ eval "$(shellwise init zsh)"
|
|
|
55
58
|
eval "$(shellwise init bash)"
|
|
56
59
|
```
|
|
57
60
|
|
|
61
|
+
## Update
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Homebrew
|
|
65
|
+
brew upgrade shellwise
|
|
66
|
+
|
|
67
|
+
# Bun
|
|
68
|
+
bun install -g shellwise@latest
|
|
69
|
+
|
|
70
|
+
# npm
|
|
71
|
+
npm install -g shellwise@latest
|
|
72
|
+
```
|
|
73
|
+
|
|
58
74
|
## Usage
|
|
59
75
|
|
|
60
76
|
### Auto-suggest (while typing)
|
|
@@ -87,12 +103,14 @@ Both `shellwise` and `sw` work as the command name:
|
|
|
87
103
|
```bash
|
|
88
104
|
shellwise search [--query <text>] # Interactive fuzzy search (Ctrl+R)
|
|
89
105
|
shellwise suggest --query <text> # Get top suggestion (used by shell hook)
|
|
90
|
-
shellwise add
|
|
106
|
+
shellwise add <cmd> # Save a command to history
|
|
107
|
+
shellwise delete [query] # Interactive search & delete a command
|
|
91
108
|
shellwise init <zsh|bash> # Output shell integration script
|
|
92
109
|
shellwise import [zsh|bash] # Import existing shell history
|
|
93
110
|
shellwise stats # Show usage statistics
|
|
94
111
|
shellwise prune --days <n> # Remove entries older than n days
|
|
95
112
|
shellwise daemon start|stop|status # Manage background daemon
|
|
113
|
+
shellwise version # Show current version
|
|
96
114
|
```
|
|
97
115
|
|
|
98
116
|
### Import existing history
|
|
@@ -139,8 +157,14 @@ shellwise import bash # Import from ~/.bash_history
|
|
|
139
157
|
## Uninstall
|
|
140
158
|
|
|
141
159
|
```bash
|
|
160
|
+
# Homebrew
|
|
161
|
+
brew uninstall shellwise
|
|
162
|
+
|
|
163
|
+
# Bun
|
|
142
164
|
bun remove -g shellwise
|
|
143
|
-
|
|
165
|
+
|
|
166
|
+
# npm
|
|
167
|
+
npm uninstall -g shellwise
|
|
144
168
|
```
|
|
145
169
|
|
|
146
170
|
Shell integration is automatically removed on uninstall. If you still see errors after uninstalling, manually remove these lines from your `~/.zshrc` (or `~/.bashrc`):
|
package/package.json
CHANGED
package/src/cli/add.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { insertCommand } from "../db/queries";
|
|
2
2
|
import { getHostname } from "../utils/platform";
|
|
3
|
-
import { IGNORED_COMMANDS } from "../utils/constants";
|
|
4
3
|
|
|
5
4
|
interface AddOptions {
|
|
6
5
|
command: string;
|
|
@@ -14,7 +13,7 @@ interface AddOptions {
|
|
|
14
13
|
export function runAdd(opts: AddOptions): void {
|
|
15
14
|
const cmd = opts.command.trim();
|
|
16
15
|
|
|
17
|
-
// Skip empty
|
|
16
|
+
// Skip empty or very short commands
|
|
18
17
|
if (!cmd || cmd.length < 2) return;
|
|
19
18
|
|
|
20
19
|
// Skip commands starting with space (convention)
|
|
@@ -23,10 +22,6 @@ export function runAdd(opts: AddOptions): void {
|
|
|
23
22
|
// Only save successful commands (exit code 0)
|
|
24
23
|
if (opts.exitCode !== undefined && opts.exitCode !== 0) return;
|
|
25
24
|
|
|
26
|
-
// Skip ignored commands (only the base command, not arguments)
|
|
27
|
-
const baseCmd = cmd.split(/\s+/)[0];
|
|
28
|
-
if (IGNORED_COMMANDS.has(baseCmd)) return;
|
|
29
|
-
|
|
30
25
|
insertCommand({
|
|
31
26
|
command: cmd,
|
|
32
27
|
cwd: opts.cwd,
|
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/daemon/server.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { getDb, closeDb } from "../db/connection";
|
|
|
2
2
|
import { insertCommand } from "../db/queries";
|
|
3
3
|
import { getHostname } from "../utils/platform";
|
|
4
4
|
import { getCommonSuggestions } from "../data/common-commands";
|
|
5
|
-
import { IGNORED_COMMANDS } from "../utils/constants";
|
|
6
5
|
import { parseRequest, getSocketPath, getPidPath, getDaemonPort } from "./protocol";
|
|
7
6
|
import { unlinkSync, writeFileSync, existsSync } from "fs";
|
|
8
7
|
import type { Socket } from "bun";
|
|
@@ -95,9 +94,6 @@ function handleRequest(raw: string): string {
|
|
|
95
94
|
const cmd = req.command.trim();
|
|
96
95
|
if (!cmd || cmd.length < 2 || cmd.startsWith(" ")) return "OK\n\n";
|
|
97
96
|
if (req.exitCode !== 0) return "OK\n\n"; // Only save successful commands
|
|
98
|
-
const baseCmd = cmd.split(/\s+/)[0];
|
|
99
|
-
if (IGNORED_COMMANDS.has(baseCmd)) return "OK\n\n";
|
|
100
|
-
|
|
101
97
|
insertCommand({
|
|
102
98
|
command: cmd,
|
|
103
99
|
cwd: req.cwd || undefined,
|
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":
|
package/src/utils/constants.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const IGNORED_COMMANDS = new Set(["ls", "cd", "pwd", "exit", "clear", "sw"]);
|